2010-12-02 2 views
0

Подходит ли дизайн ниже для вас? Это шаблон дизайна? Как бы вы улучшили его, если считаете, что он нуждается в рефакторинге?Имеет ли смысл этот дизайн?

 

public class FruitFetcher { 
    public static void main(String[] args) { 
     FruitFetcher fetcher = new FruitFetcher(); 
     Apple apple = (Apple) fetcher.fetch(new FetchAppleRequest()); 
    } 


    public Fruit fetch(FetchFruitRequest request){ 
     Fruit fruit = null; 

     if(request.getFruitName().equals(FetchAppleRequest.REQUEST_NAME)){ 
      fruit = new Apple(); 
     }else if (request.getFruitName().equals(FetchBananaRequest.REQUEST_NAME)){ 
      fruit = new Banana(); 
     } 
     return fruit; 
    } 

} 

abstract class FetchFruitRequest{ 

    abstract public String getFruitName(); 

} 

class FetchAppleRequest extends FetchFruitRequest{ 
    static String REQUEST_NAME = "Fetch_Apple"; 

    @Override 
    public String getFruitName() { 
     return REQUEST_NAME; 
    } 
} 

class FetchBananaRequest extends FetchFruitRequest{ 
    static String REQUEST_NAME = "Fetch_Banana"; 

    @Override 
    public String getFruitName() { 
     return REQUEST_NAME; 
    } 
} 

class Fruit { 
} 

class Apple extends Fruit{ 

} 

class Banana extends Fruit{ 

} 
 

В коде, клиенты FruitFetcher нужно преобразовывать Fruit к правильному типу, как вы думаете, что это правильно?


Edit: ответить на вопрос Elite Gentleman, я изменил мой код, чтобы показать, что Reqeust нужен тип, отличный от простого String.

Получает getResponse() в PaymentServer все еще выглядит «уродливым»? Как мне перефразировать его?

 


public class PaymentServer { 


    public static void main(String[] args) { 
     PaymentServer server = new PaymentServer(); 
     //set pin 
     SetPinResponse setPinResponse = (SetPinResponse) server.getResponse(new SetPinRequest("aPin")); 
     System.out.println(setPinResponse.isSuccess()); 

     //make payment 
     MakePaymentResposne makePaymentResponse = (MakePaymentResposne) server.getResponse(new MakePaymentRequest(new Money("5.00)"),"aPin")); 
     System.out.println(makePaymentResponse.isSuccess()); 
    } 




    public Response getResponse(Request request){ 
     Response aResponse = null; 

     if(request.getRequestName().equals(SetPinRequest.REQUEST_NAME)){ 
      aResponse = new SetPinResponse(); 
     }else if (request.getRequestName().equals(MakePaymentRequest.REQUEST_NAME)){ 
      aResponse = new MakePaymentResposne(); 
     } 
     return aResponse; 
    } 

} 

abstract class Request{ 
    abstract public String getRequestName(); 
} 

class SetPinRequest extends Request{ 
    static String REQUEST_NAME = "Set_Pin"; 
    private String pin; 

    SetPinRequest(String pin){ 
    this.pin = pin; 
    } 

    @Override 
    public String getRequestName() { 
     return REQUEST_NAME; 
    } 

    boolean setPin(){ 
    //code to set pin 
    return true; 
    } 
} 

class MakePaymentRequest extends Request{ 
    static String REQUEST_NAME = "Make_Payment"; 
    private Money amount; 
    private String pin; 

    MakePayment(Money amount, String pin){ 
    this.amount = amount; 
    this.pin = pin; 
    } 

    @Override 
    public String getRequestName() { 
     return REQUEST_NAME; 
    } 
} 


abstract class Response { 
    abstract protected boolean isSuccess(); 

} 

class SetPinResponse extends Response{ 

    @Override 
    protected boolean isSuccess() { 
    return true; 
    } 

} 

class MakePaymentResposne extends Response{ 
    @Override 
    protected boolean isSuccess() { 
    return false; 
    } 

} 
 

Спасибо,

Сара

+0

Благодарим Павла за редактирование. – sarahTheButterFly

+1

Почему домашняя бирка? Кажется, что самообучение выучить Java для меня. –

+0

haha..who добавил тег домашней работы? Я сделал фиктивные классы, чтобы высмеять реальный проект на работе. – sarahTheButterFly

ответ

3

Ваша конструкция очень близко к образцу фабрики. «Сборщик» - это фруктовая фабрика, вы просите плод особого типа и получаете этот плод.

Часть "запрос" выглядит несколько сложнее. Рассмотрите возможность использования перечислений:


public enum FruitType{ 
    APPLE, BANANA 
} 

public FruitFetcher { 
    public static Fruit fetch(FruitType type) { 
    switch(type) { 
     case APPLE: return new Apple(); 
     case BANANA: return new Banana(); 
    } 
    } 
    return null; 
} 

Редактировать - Это все еще довольно сложно. Требуется некоторое время, чтобы понять, чего вы хотите достичь, и это обычно показатель того, что должен быть более простой дизайн.

Первый - если ваши Request и Response классы не предлагают ничего, кроме объявлений абстрактных методов, то вы должны реорганизовать свой код код обоих типов в качестве интерфейсов. Один шаг к повышению удобочитаемости.

Во-вторых - метод getResponse может быть значительно упрощен. Вам не нужно, что (некрасиво) GetName конструкция - просто проверить тип объекта запроса:

public Response getResponse(Request request){ 
    Response aResponse = null; 

    if(request instanceof SetPinResponse) { 
     aResponse = new SetPinResponse((SetPinRequest) request); 
    } else if (request instanceof MakePaymentResposne) { 
     aResponse = new MakePaymentResposne((MakePaymentRequest) request); 
    } 

    return aResponse; 
} 
+0

Спасибо за ваш ответ Andreas_D. Это уродливый, я это почувствовал, но не знал, как его повторить. Возможно, это от общего дизайна. Невозможно пропустить все классы здесь, чтобы вы, ребята, могли посмотреть, но, по крайней мере, я получил подтверждение, что он нуждается в рефакторинге. Спасибо за ваше время. – sarahTheButterFly

-1

Подсказка: это "некрасиво" часть кода ...

if(request.getFruitName().equals(FetchAppleRequest.REQUEST_NAME)){ 
     fruit = new Apple(); 
    }else if (request.getFruitName().equals(FetchBananaRequest.REQUEST_NAME)){ 
     fruit = new Banana(); 
+3

Хорошо, как это помогает? –

1

Помимо дизайн шаблона, что вы ищете является Generics.

Что касается дизайна модели, что вы делаете, называется Factory Method Pattern, где FruitFetcher является завод и Fruit (и его подклассы) являются продукты.


Вашего FruitFetcher.fetch немного «неоднозначный» (из-за отсутствие лучшего слова). Я бы предложил передать type, который идентифицирует Fruit, который вы запрашиваете.

type может быть перечисление, целое число, или строка (это зависит от того, как вы хотите, чтобы создать определенный тип значения, которое может быть признана FruitFetcher.fetch()

. Пример:

public class FruitFetcher { 

    public Fruit fetch(String fruitName) { 
     if ("Apple".equals(fruitName)) { 
      return new Apple(); 
     } 

     if ("Banana".equals(fruitName)) { 
      return new Banana(); 
     } 

     return null; 
    } 
} 

Это более красноречиво, чем отправка new FetchAppleRequest() или new FetchBananaRequest().

+0

Я понимаю, что вы говорите. Но как насчет того, когда FetchAppleRequest содержит больше всего типа Fruit? Может быть, мой пример с фруктами здесь не подходит. Но я имею в виду, что параметр fetch должен быть типом, отличным от простого String или enum. – sarahTheButterFly

+0

Уточните пожалуйста. Если у вас сложный тип, у вас будет [шаблон стратегии] (http://en.wikipedia.org/wiki/Strategy_pattern), который будет обрабатывать эти сложности. –

+0

Я редактировал свой пост. – sarahTheButterFly