Группа 10 назначена на курс Алгебра 3 страница

Раздутый контроллер (волшебный сервлет) выполняет слишком много обязанностей. Признаки:

· в системе имеется единственный класс контроллера, получающий все системные сообщения, которых поступает слишком много (внешний или ролевой контроллер);

· контроллер имеет много полей (информации) и методов (ассоциаций), которые необходимо распределить между другими классами.

Шаблоны проектирования GoF

Шаблоны проектирования GoF – это многократно используемые решения широко распространенных проблем, возникающих при разработке программного обеспечения. Многие разработчики искали пути повышения гибкости и степени повторного использования своих программ. Найденные решения воплощены
в краткой и легко применимой на практике форме.

«Любой шаблон описывает задачу, которая снова и снова возникает в нашей работе, а также принцип ее решения, причем таким образом, что это решение можно потом использовать миллион раз, ничего не изобретая заново». (Кристо­фер Александер).

В общем случае шаблон состоит из четырех основных элементов:

1. Имя. Точное имя предоставляет возможно сразу понять проблему и
определить решение. Уровень абстракции при проектировании повышается.

2. Задача. Область применения в рамках решения конкретной проблемы.

3. Решение. Абстрактное описание элементов дизайна задачи проекти­рования и способа ее решения с помощью обобщенного набора классов.

4. Результаты.

Шаблоны классифицируются по разным критериям, наиболее распростра­ненным из которых является назначение шаблона. Вследствие этого выделяются порождающие шаблоны, структурные шаблоны и шаблоны поведения.

Порождающие шаблоны

Порождающие шаблоны предназначаются для организации процесса создания объектов.

К порождающим шаблонам относятся:

Abstract Factory(Абстрактная Фабрика) – предоставляет интерфейс для создания связанных между собой объектов семейств классов без указания их конкретных реализаций;

Factory(Фабрика) – создает объект из иерархического семейства классов на основе передаваемых данных (частный случай Abstract Factory);

Builder(Строитель) – создает объект класса различными способами;

Singleton(Одиночка) – гарантирует существование только одного экземпля­ра класса;

Prototype(Прототип) – применяется при создании сложных объектов. На основе прототипа объекты сохраняются и воссоздаются, н-р путем копирования;

Factory Method(Фабричный Метод) – определяет интерфейс для создания объектов, при этом объект класса создается с помощью методов подклассов.

Шаблон Factory

Необходимо определить механизм создания объектов по заданному признаку для классов, находящихся в иерархической структуре. Основной класс шаблона представляет собой класс, который имеет методы для создания одного объекта из нескольких возможных на основе передаваемых данных.

Рис. 5.6. Пример реализации шаблона Factory

Решением проблемы может быть создание класса ClassFactory с одним методом getClassFromFactory(String id), возвращаемым значением которого будет ссылка на класс-вершину Base иерархии создаваемых классов.
В качестве параметра метода передается некоторое значение, в соответствии с которым будет осуществляться инициализация объекта одного из подклассов класса Base.

Программная реализация может быть представлена в общем виде следующим образом.

/*пример # 10 : создание объектов с помощью шаблона Factory : Base.java : First.java : Second.java : ClassFactory.java : Main.java */

packagechapt05.factory;

public abstract class Base {

public abstract void perform();

}

packagechapt05.factory;

public class First extends Base {

public void perform() {

System.out.println("First");

}

}

packagechapt05.factory;

public class Second extends Base {

public void perform() {

System.out.println("Second");

}

}

packagechapt05.factory;

public class ClassFactory {

private enum Signs {FIRST, SECOND}

public static Base getClassFromFactory(String id) {

Signs sign = Signs.valueOf(id.toUpperCase());

switch(sign){

case FIRST : return new First();

case SECOND : return new Second();

default: throw new EnumConstantNotPresentException(

Signs.class, sign.name());

}

}

}

packagechapt05.factory;

public class Main {

public static void main(String args[]) {

Base ob1 =

ClassFactory.getClassFromFactory("first");

Base ob2 =

ClassFactory.getClassFromFactory("second");

ob1.perform();

ob2.perform();

}

}

Один из примеров применения данного шаблона уже был рассмотрен в примере # 5 предыдущей главы.

Шаблон AbstractFactory

Необходимо создавать объекты классов, не имеющих иерархической связи, но логически связанных между собой. Абстрактный класс-фабрика определяет общий интерфейс таких фабрик. Его подклассы обладают конкретной реализа­цией методов по созданию разных объектов.

Предложенное решение изолирует конкретные классы. Так как абстрактная фабрика реализует процесс создания классов-фабрик и саму процедуру ини­циа­лизации объектов, то она изолирует приложение от деталей реализации классов.

Одна из возможных реализаций шаблона предложена в следующем примере. Классы фабрики создаются по тому же принципу, по которому в предыдущем шаблоне создавались объекты.

/*пример # 11 : создание классов-фабрик по заданному признаку :

AbstractFactory.java */

packagechapt05.abstractfactory;

public class AbstractFactory {

enum Color { BLACK, WHITE };

public static BaseFactory getFactory(String data) { Color my = Color.valueOf(data.toUpperCase());

switch (my){

case BLACK : return new BlackFactory();

case WHITE : return new WhiteFactory();

default : throw new

EnumConstantNotPresentException(Signs.class, sign.name());

}

}

}

Рис. 5.7. Пример реализации шаблона AbstractFactory

Производители объектов реализуют методы по созданию не связанных иерархическими зависимостями объектов. Класс BaseFactory – абстрактная фабрика, а классы BlackFactory и WhiteFactory конкретные производители объектов, наследуемые от нее. Конкретные фабрики могут создавать черные или белые объекты-продукты.

/*пример # 12 : классы-фабрики по созданию несвязанных объектов :

BaseFactory.java : BlackFactory.java : WhiteFactory.java */

packagechapt05.abstractfactory;

public abstract class BaseFactory {

public abstract Circle createCircle(double radius);

public abstract Triangle createTriangle(double a,

double b);

}

packagechapt05.abstractfactory;

public class BlackFactory extends BaseFactory {

public Circle createCircle(double radius) {

return new BlackCircle(radius);

}

publicTriangle createTriangle(double a, doubleb){

return newBlackTriangle(a,b);

}

}

packagechapt05.abstractfactory;

public class WhiteFactory extends BaseFactory {

publicCircle createCircle(double radius) {

return new WhiteCircle(radius);

}

publicTriangle createTriangle(double a, doubleb){

return new WhiteTriangle(a, b);

}

}

Рассматриваются два вида классов-продуктов: Circle, Triangle. Каждый из них может быть представлен в одном из двух цветов: белом или
черном.

/*пример # 13 : классы-продукты : Circle.java : Triangle.java */

packagechapt05.abstractfactory;

public abstract class Circle {

protected double radius;

protectedString color;

public abstract void square();

}

packagechapt05.abstractfactory;

public class BlackCircle extends Circle {

public BlackCircle(double radius){

this.radius = radius;

color = "Black";

}

public void square(){

double s = Math.PI * Math.pow(radius, 2);

System.out.println(color + " Circle"

+ " Square = " + s);

}

}

packagechapt05.abstractfactory;

public class WhiteCircle extends Circle{

public WhiteCircle(double radius){

this.radius = radius;

color = "White";

}

public void square(){

double s = Math.PI * Math.pow(radius, 2);

System.out.println(color + " Circle "

+ "Square = " + s);

}

}

packagechapt05.abstractfactory;

public abstract class Triangle {

protected double a, b;

protectedString color;

public abstract void square();

}

packagechapt05.abstractfactory;

public class BlackTriangle extends Triangle {

public BlackTriangle (double a, double b){

this.a = a;

this.b = b;

color = "Black";

}

public void square(){

double s = a * b / 2;

System.out.println(color + " Triangle"

+ " Square = " + s);

}

}

packagechapt05.abstractfactory;

public class WhiteTriangle extends Triangle {

public WhiteTriangle (double a,double b) {

this.a = a;

this.b = b;

color = "White";

}

public void square(){

double s = 0.5 * a * b;

System.out.println(color + " Triangle"

+ " Square = " + s);

}

}

Ниже будут созданы объекты всех классов и всех цветов.

/*пример # 14 : демонстрация работы шаблона AbstractFactory : Main.java */

packagechapt05.abstractfactory;

public class Main {

public static void main(String[] args) {

BaseFactory factory1 =

AbstractFactory.getFactory("black");

BaseFactory factory2 =

AbstractFactory.getFactory("white");

Circle ob1 = factory1.createCircle(1.232);

Circle ob2 = factory2.createCircle(1);

Triangle ob3 = factory1.createTriangle(12,5);

Triangle ob4 = factory2.createTriangle(1,7);

ob1.square();

ob2.square();

ob3.square();

ob4.square();

}

}

Шаблон Builder

Необходимо задать конструирование сложного объекта, определяя для него только тип и содержимое. Детали построения объекта остаются скрытыми.

Рис. 5.8. Пример реализации шаблона Builder

Класс BaseBuilderопределяет абстрактный интерфейс для создания частей объекта сложного класса User. Классы XMLBuilder и DBBuilder конструируют и собирают вместе части объекта класса User, а также представляет внешний интерфейс для доступа к нему. В результате объекты-строители могут работать с разными источниками, определяющими содержимое, не требуя при этом никаких изменений. При использовании этого шаблона появляется возможность контролировать пошагово весь процесс создания объекта-продукта.

Простая реализация шаблона Builder приведена ниже.

/*пример # 15 : «сложный» для построения объект : User.java */

packagechapt05.builder;

public class User {

private String login = "Guest";

private String password = "Kc";

public String getLogin() {

return login;

}

public void setLogin(String login) {

this.login = login;

}

public String getPassword() {

return password;

}

public void setPassword(String password) {

this.password = password;

}

}

Класс BaseBuilder – абстрактный класс-строитель, объявляющий в ка­честве поля ссылку на создаваемый объект и абстрактные методы его построения. Классы XMLBuilder и DBBuilder – наследуемые от него классы, реализующие специальные способы создания объекта. Таким образом, используя один класс User можно создать или администратора или модератора.

/*пример # 16 : разные способы построения объекта : BaseBuilder.java : XMLBuilder.java: DBBuilder.java */

packagechapt05.builder;

public abstract class BaseBuilder {

protected User user = new User();

public User getUser() {

return user;

}

public abstract void buildLogin();

public abstract void buildPassword();

}

packagechapt05.builder;

public class XMLBuilder extends BaseBuilder {

public void buildLogin() {

//реализация

user.setLogin("Admin");

}

public void buildPassword() {

//реализация

user.setPassword("Qu");

}

}

packagechapt05.builder;

public class DBBuilder extends BaseBuilder {

public void buildLogin() {

//реализация

user.setLogin("Moderator");

}

public void buildPassword() {

//реализация

user.setPassword("Ku");

}

}

Процесс создания объектов с использованием одного принципа реализован ниже.

/*пример # 17 : тестирование процесса создания объекта : Main.java */

packagechapt05.builder;

public class Main {

private static User buildUser(BaseBuilder builder) {

builder.buildLogin();

builder.buildPassword();

return builder.getUser();

}

public static void main(String args[]) {

User e1 = buildUser(new XMLBuilder());

User e2 = buildUser(new DBBuilder());

System.out.println(e1.getLogin());

System.out.println(e1.getPassword());

System.out.println(e2.getLogin());

System.out.println(e2.getPassword());

}

}

Шаблон Singleton

Необходимо создать объект класса таким образом, чтобы гарантировать невозможность инициализации другого объекта того же класса. Обычно сам класс контролирует наличие единственного экземпляра и он же предоставляет при необходимости к нему доступ.

/*пример # 18 : реализация шаблона «Одиночка» : Singleton.java */

packagechapt05.singleton;

public class Singleton {

private static Singleton instance = null;

private SingletonTrust() {

}

public static Singleton getInstance() {

if (instance == null) {

System.out.println("Creating Singleton");

instance = new Singleton();

}

return instance;

}

}

Класс объявляет метод getInstance(), который позволяет клиентам получать контролируемый доступ к единственному экземпляру. Этот шаблон позволяет уточнять методы через подклассы, а также разрешить появление более чем одного экземпляра.

Структурные шаблоны

Структурные шаблоны отвечают за композицию объек­тов и классов.

К структурным шаблонам относятся:

Proxy(Заместитель) – подменяет сложный объект более простым и осуществляет контроль доступа к нему;

Composite(Компоновщик) – группирует объекты в иерархические структуры и позволяет работать с единичным объ­ектом так же, как с группой объектов;

Adapter(Адаптер) – применяется при необходимости использовать вместе несвязанные классы. Поведение адаптируемого класса при этом изменяется на необходимое;

Bridge(Мост) – разделяет представление класса и его реализацию, позволяя независимо изменять то и другое;

Decorator(Декоратор) – представляет способ изменения поведения объекта без создания подклассов. Позволяет использовать поведение одного объекта в другом;

Facade(Фасад) – создает класс с общим интерфейсом высокого уровня к некоторому числу интерфейсов в подсистеме.

Шаблон Bridge

Необходимо отделить абстракцию (Abstraction) от ее реализации (Implementor) так, чтобы и то и другое можно было изменять независимо. Шаблон Bridge используется в тех случаях, когда существует иерархия абстракций и соответствующая иерархия реализаций. Причем не обязательно точное соответствие между абстракциями и реализациями. Обычно абстракция определяет операции более высокого уровня, чем реализация.

Рис. 5.9. Пример реализации шаблона Bridge

/*пример # 18 : Implementor и его подкласс : Color.java: YellowColor.java */

package chapt05.implementor;

public abstract class Color { //implementor

public abstract void useBrush();

}

package chapt05.implementor;

public class YellowColor extends Color {

public void useBrush() {

System.out.println("BrushColor - Yellow");

}

}

Класс Color – абстрактный, реализующий Implementor. Класс
YellowColor – уточняющий подкласс класса Color.

/*пример # 19 : абстракция и ее уточнения : Shape.java : Circle.java :

Rectangle.java */

package chapt05.abstraction;

import chapt05.implementor.*;

public abstract class Shape { //abstraction

protected Color color;

public Shape (){

color = null;

}

public Color getColor() {

return color;

}

public void setColor(Color color) {

this.color = color;

}

public abstract void performWithColor();

}

package chapt05.abstraction;

import chapt05.implementor.*;

public class Circle extends Shape {

public Circle(Color color) {

setColor(color);

}

public void performWithColor() {

System.out.println("Performing in Circle class");

color.useBrush();

}

}

package chapt05.abstraction;

import chapt05.implementor.*;

public class Rectangle extends Shape {

public Rectangle(Color color) {

setColor(color);

}

public void performWithColor() {

System.out.println("Performing in Rectangle class");

color.useBrush();

}

}

Класс Shape – абстракция, классы Circle и Rectangle – уточненные абстракции.

/*пример # 20 : использование шаблона Bridge : Main.java */

package chapt05.bridge;

import chapt05.abstraction.*;

import chapt05.implementor.*;

public class Main {

public static void main(String args[]) {

YellowColor color = new YellowColor();

new Rectangle(color).performWithColor();

new Circle(color).performWithColor();

}

}

Реализация больше не имеет постоянной привязки к интерфейсу. Реализацию абстракции можно динамически изменять и конфигурировать во время выполнения. Иерархии классов Abstraction и Implementor независимы и поэтому могут иметь любое число подклассов.

Шаблон Decorator

Необходимо расширить функциональные возможности объекта, используя прозрачный для клиента способ. Расширяемый класс реализует тот же самый интерфейс, что и исходный класс, делегируя исходному классу выполнение базовых операций. Шаблон Decorator даёт возможность динамического изменения поведения объектов в процессе выполнения приложения.

Рис. 5.10. Пример реализации шаблона Decorator

/*пример # 21 : определение интерфейса для компонентов : Driver.java */

package chapt05.decorator;

public abstract class Driver {

public abstract void do();

}

Класс DriverDecorator определяет для набора декораторов интерфейс, соответствующий интерфейсу класса Driver, и создает необходимые ссылки.

/*пример # 22 : интерфейс-декоратор для класса Driver : DriverDecorator.java */

package chapt05.decorator;

public abstract class DriverDecorator extends Driver {

protected Driver driver;

public DriverDecorator(Driver driver) {

this.driver = driver;

}

public void do() {

driver.do();

}

}

Класс CarDriver определяет класс, функциональность которого будет расширена.

/*пример # 23 : класс просто водителя : CarDriver.java */

package chapt05.decorator;

public class CarDriver extends Driver {

public void do() { //базовая операция

System.out.println("I am a driver");

}

}

Класс BusDriver добавляет дополнительную функциональность
addedBehaviorOne() необходимую для водителя автобуса, используя функциональность do() класса CarDriver.

/*пример # 24 : класс водителя автобуса: BusDriver.java */

package chapt05.decorator;

public class BusDriver extends DriverDecorator {

public BusDriver(Driver driver) {

super(driver);

}

private void addedBehaviorOne() {

System.out.println("I am bus driver");

}

public void do() {

driver.do();

addedBehaviorOne();

}

}

Класс CarDriverAndForwardingAgent добавляет дополнительную функциональность addedBehaviorTwo() необходимую для водителя-экспедитора, используя функциональность do() класса CarDriver.

/*пример # 25 : класс водителя-экспедитора:CarDriverAndForwardingAgent.java*/

package chapt05.decorator;

public class CarDriverAndForwardingAgent

extends DriverDecorator {

public CarDriverAndForwardingAgent(Driver driver){

super(driver);

}

private void addedBehaviorTwo() {

System.out.println("I am a Forwarding Agent");

}

public void do() {

driver.do();

addedBehaviorTwo();

}

}

Создав экземпляр класса CarDriver можно делегировать ему выполнение задач, связанных с водителем автобуса или водителя-экспедитора, без написания специализированных полновесных классов.

/*пример # 26 : использование шаблона Decorator : Main.java */

package chapt05.decorator;

public class Main {

public static void main(String args[]){

Driver carDriver = new CarDriver();

Main runner = new Main();

runner.doDrive(carDriver);

runner.doDrive(new BusDriver(carDriver));

runner.doDrive(

new CarDriverAndForwardingAgent(carDriver));

}

public void doDrive(Driver driver){

driver.do();

}

}

Шаблоны поведения

Шаблоны поведения характеризуют способы взаимодействия классов или объектов между собой.

К шаблонам поведения относятся:

Chain of Responsibility(Цепочка Обязанностей) – организует независимую от объекта-отправителя цепочку не знающих возможностей друг друга объектов-получателей, которые передают запрос друг другу;

Command (Команда) – используется для определения по некоторому признаку конкретного класса, которому будет передан запрос для обработки;

Iterator(Итератор) – позволяет последовательно обойти все элементы коллекции или другого составного объекта, не зная деталей внутреннего представления данных;

Mediator(Посредник) – позволяет снизить число связей между классами при большом их количестве, выделяя один класс, знающий все о методах других классов;

Memento(Хранитель) – сохраняет текущее состояние объекта для дальнейшего восстановления;

Observer(Наблюдатель) – позволяет при зависимости между объектами типа «один ко многим» отслеживать изменения объекта;

Наши рекомендации