
Порождающие паттерны
В предыдущей главе мы столкнулись с необходимостью разделения места определения объекта и места его создания. Это видно на примере определения рисуемой фигуры и создания рисуемой фигуры. Определяем фигуру в конструкторе MyFrame
shape = new MyShape(new Rectangle2D.Double(),new ColorShape(Color.GREEN));
и устанавливаем фигуру в контроллере.
controller.setMyShape(shape);
Создаем новую фигуру в модели с помощью метода executePress класса DrawAction.
public void executePress(Model model,Point2D point) {
p[0]=point;
model.setNewActiveShape();
model.add();
}
Для решения такой проблемы могут быть использованы различные порождающие паттерны, которые абстрагируют процесс создания объекта. Они позволяют сделать систему независимой от способа создания, композиции и представления объектов. Шаблон, порождающий классы, использует наследование, чтобы изменять создаваемый класс, а шаблон, порождающий объекты, делегирует создание другому объекту.
Паттерн фабричный метод
Фабричный метод предоставляет подклассам интерфейс для создания экземпляров некоторого класса. В момент создания наследники могут определить, какой класс создавать. Иными словами, Фабрика делегирует создание объектов наследникам родительского класса. Это позволяет использовать в коде программы не специфические классы, а манипулировать абстрактными объектами на более высоком уровне. Также известен под названием виртуальный конструктор (Virtual Constructor).
Рассмотрим использование паттерна «фабричный метод» в нашем графическом редакторе.
Создадим интерфейс для создания экземпляров классов фигур различной формы.
public interface ShapeMaker {
RectangularShape createShape();
}
Пусть этот интерфейс наследуют классы, которые создают классы прямоугольников и эллипсов.
public class RectangleCreator implements ShapeMaker{
public RectangularShape createShape() {
return new Rectangle2D.Double();
}
}
public class EllipseCreator implements ShapeMaker{
public RectangularShape createShape() {
return new Ellipse2D.Double();
}
}
Тогда, применяя метод createShape к объектам типа ShapeMaker можно получить новые объекты соответствующего типа. Например, имеется объект
ShapeMaker rectangleCreator = new RectangleCreator();
В любой момент можно вызвать метод createShape и создать прямоугольник или эллипс
RectangularShape s =rectangleCreator.createShape();
s = new EllipseCreator().createShape();
Аналогичным образом поступим с закрашенными и незакрашенными фигурами.
Создадим абстрактный класс для создания закрашенных фигур и фигур с контуром различного цвета. Цвет будем хранить в переменной color, доступной для обеих реализаций интерфейса ColorBehavior.
public abstract class ColorBehaviorMaker {
protected Color color;
public ColorBehaviorMaker(Color c){
color = c;
}
public ColorBehaviorMaker(){
color = Color.BLACK;
}
public abstract ColorBehavior createColorBehavior();
public void setColor(Color color) {
this.color = color;
}
}
Пусть этот интерфейс наследуют классы, которые создают реализации интерфейса ColorBehavior.
public class ColorShapeCreator extends ColorBehaviorMaker{
public ColorShapeCreator(Color c){
super(c);
}
public ColorShapeCreator(){super(Color.BLACK);}
public ColorBehavior createColorBehavior() {
return new ColorShape(color);
}
}
public class NoColorCreator extends ColorBehaviorMaker{
public NoColorCreator(Color color){
super(color);
}
public NoColorCreator(){super(Color.BLACK);}
@Override
public ColorBehavior createColorBehavior() {
return new NoColorShape(color);
}
}
Тогда, применяя метод createColorBehavior к объектам типа ColorBehaviorMaker можно получить новые объекты соответствующего типа. Например, имеется объект colorShapeCreator.
ColorBehaviorMaker colorShapeCreator = new ColorShapeCreator();
Установим цвет будущей фигуры colorShapeCreator.setColor(Color.yellow);
Имея объект colorShapeCreator можно в любой момент создать закрашенную фигуру.
ColorBehavior colorShape = colorShapeCreator.createColorBehavior();
Применим написанные классы для создания новой фигуры с соответствующими свойствами.
shape = new MyShape(rectangleCreator.createShape(),colorShapeCreator.createColorBehavior());
Передавать экземпляры двух классов, необходимых для создания фигуры неудобно. Поэтому создадим новый класс MyShapeCreator.
public class MyShapeCreator {
private ShapeMaker shapeMaker;
private ColorBehaviorMaker colorBehaviorMaker;
public MyShapeCreator(){
shapeMaker = new RectangleCreator();
colorBehaviorMaker = new NoColorCreator();
}
public void setShapeMaker(ShapeMaker shapeMaker) {
this.shapeMaker = shapeMaker; }
public void setColorBehaviorMaker(ColorBehaviorMaker colorBehaviorMaker) {
this.colorBehaviorMaker = colorBehaviorMaker;
}
public MyShape createMyShape(){
return new MyShape(shapeMaker.createShape(),colorBehaviorMaker.createColorBehavior());
}
}