#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 }
Комментариев нет:
Отправить комментарий