#java #шаблоны_проектирования
Закрыт. Этот вопрос не по теме. Ответы на него в данный
момент не принимаются.
Хотите улучшить этот вопрос? Update the question so it's
on-topic for Stack Overflow на русском.
Закрыт 4 года назад.
Здравствуйте !!!
Недавно, я приступил к изучению паттернов проектирования. Один из самых первых паттернов,
который был реализован - это Builder. Какие у Вас есть замечания по данной реализации.
Заранее спасибо !
Исходный код:
1) Абстрактный класс BaseCarBuilder.
public abstract class BaseCarBuilder {
public abstract void buildCategory(CategoryCar pCategoryCar);
public abstract void buildCarcass(CarcassType pCarcassType) ;
public abstract void buildEngine(Engine pEngine);
public abstract void buildColorCarcass(ColorCar pColorCar) ;
public abstract void buildDoors(int pDoors) ;
public Car getBuiltCar() {
return null;
}
}
2) Класс Car.
public class Car {
public final static int TWO_DOORS = 2;
public final static int THREE_DOORS = 3;
public final static int FOUR_DOORS = 4;
public final static int FIVE_DOORS = 5;
private int doorsCount;
private Engine engine;
private String carName;
private ColorCar colorCar;
private CarcassType carcassType;
private CategoryCar categoryCar;
public Car(String pCarName) {
this.carName = pCarName;
}
public ColorCar getColorCar() {
return colorCar;
}
public void setColorCar(ColorCar colorCar) {
this.colorCar = colorCar;
}
public CarcassType getCarcassType() {
return carcassType;
}
public void setCarcassType(CarcassType carcassType) {
this.carcassType = carcassType;
}
public CategoryCar getCategoryCar() {
return categoryCar;
}
public void setCategoryCar(CategoryCar categoryCar) {
this.categoryCar = categoryCar;
}
public int getDoorsCount() {
return doorsCount;
}
public void setDoorsCount(int doorsCount) {
this.doorsCount = doorsCount;
}
public Engine getEngine() {
return engine;
}
public void setEngine(Engine engine) {
this.engine = engine;
}
public String getCarInfo() {
String info =
"car name = " + carName
+ " *** category car = " + categoryCar
+ " *** carcass tape = " + carcassType
+ " *** engine = " + engine
+ " *** color = " + colorCar
+ " *** count doors = " + doorsCount;
System.err.println("---------------------------------------------------");
return info;
}
}
3) Класс MersedesBenzBuilder, который наследуется от BaseCarBuilder.
public class MersedesBenzBuilder extends BaseCarBuilder {
private Car car;
public MersedesBenzBuilder() {
car = new Car("Mersedes Benz");
}
@Override
public void buildCategory(CategoryCar pCategoryCar) {
car.setCategoryCar(pCategoryCar);
}
@Override
public void buildCarcass(CarcassType pCarcassType) {
car.setCarcassType(pCarcassType);
}
@Override
public void buildDoors(int pDoors) {
car.setDoorsCount(pDoors);
}
@Override
public void buildEngine(Engine pEngine) {
car.setEngine(pEngine);
}
@Override
public void buildColorCarcass(ColorCar pColorCar) {
car.setColorCar(pColorCar);
}
}
4) Есть класс Директор (Диспетчер).
public class Director {
public Car buildNewCar(BaseCarBuilder carBuilder, CategoryCar pCategoryCar,
CarcassType pCarcassType, int pDoors, Engine pEngine,
ColorCar pColorCar) {
Car tempCar = null;
if (carBuilder != null) {
carBuilder.buildCategory(pCategoryCar);
carBuilder.buildCarcass(pCarcassType);
carBuilder.buildDoors(pDoors);
carBuilder.buildEngine(pEngine);
carBuilder.buildColorCarcass(pColorCar);
tempCar = carBuilder.getBuiltCar();
} else {
final String nullPoint = "Yoa are not create car_builder";
Exception exception = new NullPointerException(nullPoint);
exception.printStackTrace();
}
return tempCar;
}
}
5) Класс который запускает этот паттерн RunBuilderPattern.
public class RunBuilderPattern {
public static void main(String[] args) {
Car car = null;
Director director = new Director();
MersedesBenzBuilder mersedesBenzBuilder = new MersedesBenzBuilder();
car = director.buildNewCar(
mersedesBenzBuilder,
CategoryCar.SPORT_CAR,
CarcassType.CABRIOLET,
Car.TWO_DOORS, Engine.PETROL,
ColorCar.RED);
System.out.println("CAR INFO: " + car.getCarInfo());
}
}
6) Дополнительные классы, точнее Enum-ы:
public enum CarcassType {
SEDAN, UNIVERSAL, CABRIOLET, HATCHBACK, COUPE, LIMOUSINE
}
public enum CategoryCar {
CARGO, PASSENGER, BUS, SPORT_CAR
}
public enum ColorCar {
BLACK, WHITE, RED, GREEN, BLUE, ORANGE, BROWN
}
public enum Engine {
DIZEL, PETROL, GAZ, HUBRID
}
7) Вот что выводится в консоль:
CAR INFO: car name = Mersedes Benz *** category car = SPORT_CAR *** carcass tape
= CABRIOLET *** engine = PETROL *** color = RED *** count doors = 2
Жду Ваших замечаний, советов, ругани и брани !!!
Ответы
Ответ 1
Всегда пожалуйста: public abstract class BaseCarBuilder { // Мне почему-то кажется, что для примера можно было обойтись двумя-тремя // методами вида buildSomething. Ваш текущий код — это один большой // boilerplate, где из-за геттеров и сеттеров теряется смысл. public abstract void buildCategory(CategoryCar pCategoryCar); // Carcass — крайне неудачный термин. См. http://goo.gl/SCMO1q public abstract void buildCarcass(CarcassType pCarcassType) ; // Параметры с именами вида pSomething не следуют naming convention. // Если бы вы, кстати, инвертировали слова в именах вида pColorCar ----> // carColor (или просто color), уже стало бы лучше и понятнее. // pCategoryCar в текущем варианте означает что-то в духе "машина с // какой-то там категорией", а используется в значении "категория машины". public abstract void buildEngine(Engine pEngine); // Опять-таки, плывет нейминг. В текущем варианте по названиям методов // получается, что ваш builder можно попросить сделать "просто carcass", а // можно "цветной carcass". Почему бы не объединить buildColorCarcass и // buildCarcass в один метод или просто сделать buildCarcass + buildColor? public abstract void buildColorCarcass(ColorCar pColorCar) ; // Эти замечания — не очень принципиальные. См. ниже. public abstract void buildDoors(int pDoors) ; public Car getBuiltCar() { return null; } public class Car { // public final static int TWENTY_ELEVEN_DOORS = 2011. Почему не enum? public final static int TWO_DOORS = 2; public final static int THREE_DOORS = 3; public final static int FOUR_DOORS = 4; public final static int FIVE_DOORS = 5; private int doorsCount; private Engine engine; private String carName; private ColorCar colorCar; private CarcassType carcassType; private CategoryCar categoryCar; public Car(String pCarName) { this.carName = pCarName; } public ColorCar getColorCar() { return colorCar; } .... public Engine getEngine() { return engine; } public void setEngine(Engine engine) { this.engine = engine; } // Погодите, а не 'toString' ли это, часом? Вы, кстати, задумались над тем, // что, если написать в *произвольном* месте кода вот это, // // [[[ // String info = car.getCarInfo(); // info = car.getCarInfo(); // info = car.getCarInfo(); // ...... // info = car.getCarInfo(); // ]]] // // то ваш stderr окажется зафлужен строчками вида "------------------"? public String getCarInfo() { String info = "car name = " + carName + " *** category car = " + categoryCar + " *** carcass tape = " + carcassType + " *** engine = " + engine + " *** color = " + colorCar + " *** count doors = " + doorsCount; System.err.println("---------------------------------------------------"); return info; } } public class MersedesBenzBuilder extends BaseCarBuilder { private Car car; public MersedesBenzBuilder() { car = new Car("Mersedes Benz"); } @Override public void buildCategory(CategoryCar pCategoryCar) { car.setCategoryCar(pCategoryCar); } .... @Override public void buildColorCarcass(ColorCar pColorCar) { car.setColorCar(pColorCar); } } public class Director { public Car buildNewCar(BaseCarBuilder carBuilder, CategoryCar pCategoryCar, CarcassType pCarcassType, int pDoors, Engine pEngine, ColorCar pColorCar) { // Вот, теперь к главному. Вы неправильно поняли Builder по Gang of // Four, и поэтому получилась чушь. При изучении паттернов один из самых // важных принципов, как бы банально это не звучало, заключается в том, // чтобы *четко* следовать тому, что написано. Давайте внимательно // посмотрим на UML-диаграмму для паттерна Builder (http://goo.gl/rX9gMN). // Сколько параметров у метода Director.construct? Один. А у вас сколько? // Сколько параметров у метода Builder.buildPart? Ноль. А у вас сколько? // А что это значит? Правильно, что вы неверно истолковали суть этого // паттерна. // В паттерне Builder важен следующий инвариант: как только объект // ConcreteBuilder создан, он более не допускает параметризации извне. // Идея заключается в том, что конкретный экземпляр Builder умеет // каким-то своим способом совершать "маленькие шажки" к созданию // объекта (buildPart), а Director умеет объединять шажки из интерфейса // Builder таким образом, чтобы получился объект. // Конкретно в вашем случае детали типа Engine.PETROL и // CategoryCar.SPORT_CAR должны были быть "зашиты" в реализации класса // MersedesBenzBuilder. А у вас получилась такая штука, что вы вместо // Builder'a сделали крайне неочевидный named constructor, который // весело перебрасывает аргументы туда-сюда. // Годную реализацию этого паттерна на Java можете посмотреть здесь — // http://goo.gl/KRk1L // Также рекомендую вам ознакомиться с паттерном Fluent Builder — // http://goo.gl/HIulBb // И да, паттерны обычно тем или иным способом решают какую-то // прикладную задачу. Поэтому "приступать к изучению паттернов," не // имея под рукой хорошей задачи — это довольно плохая идея. Придумайте // себе хорошую задачу и пытайтесь применять паттерны для ее решения, а // не придумывайте задачи, чтобы применить паттерны. // Хороший пример такой задачи как раз и приводится в книге GoF // (http://www.amazon.com/dp/0201633612), где они step-by-step // разрабатывают текстовый редактор. Car tempCar = null; if (carBuilder != null) { carBuilder.buildCategory(pCategoryCar); carBuilder.buildCarcass(pCarcassType); carBuilder.buildDoors(pDoors); carBuilder.buildEngine(pEngine); carBuilder.buildColorCarcass(pColorCar); // Я, кстати, вообще не понимаю, как это может работать, поскольку // в вашем коде метод getBuiltCar всегда возвращает null. tempCar = carBuilder.getBuiltCar(); } else { // Простите, здесь у меня просто глаза вытекли. final String nullPoint = "Yoa are not create car_builder"; Exception exception = new NullPointerException(nullPoint); exception.printStackTrace(); } return tempCar; } } // Какое сказочное название для класса :) public class RunBuilderPattern { public static void main(String[] args) { Car car = null; Director director = new Director(); MersedesBenzBuilder mersedesBenzBuilder = new MersedesBenzBuilder(); // Ух ты! Смотрите! Я на самом деле работаю как простой конструктор, // но два раза разворачиваю и заворачиваю параметры. car = director.buildNewCar( mersedesBenzBuilder, CategoryCar.SPORT_CAR, CarcassType.CABRIOLET, Car.TWO_DOORS, Engine.PETROL, ColorCar.RED); System.out.println("CAR INFO: " + car.getCarInfo()); } } // ... а вот эти штуки неплохо бы переместить в класс Car. public enum CarcassType { SEDAN, UNIVERSAL, CABRIOLET, HATCHBACK, COUPE, LIMOUSINE } public enum CategoryCar { CARGO, PASSENGER, BUS, SPORT_CAR } public enum ColorCar { BLACK, WHITE, RED, GREEN, BLUE, ORANGE, BROWN } public enum Engine { DIZEL, PETROL, GAZ, HUBRID }
Комментариев нет:
Отправить комментарий