предисловие
[Разработчик]: Босс, вы научили меня множеству паттернов проектирования, вы закончили учить их все?
[БОСС]: Нет, есть еще несколько шаблонов проектирования, о которых я еще не говорил. Сегодня я научу вас еще трем. Это шаблон строителя, шаблон цепочки ответственности и шаблон меморандума. Как насчет этого? ?
[Разработчик]: Ну, больше всего мне нравится учиться!
режим строителя
намерение
Он представляет конструкцию и ее разделение сложного объекта, так что один и тот же процесс сборки может создавать разные представления.
основной код
"Определить интерфейс построения"
public interface Builder {
void buildPartOne();
void buildPartTwo();
void buildPartThr();
/***
* 一般情况肯定是一个复杂的对象
*/
String getResult();
}
"Определить фактического строителя"
public class ConcreteBuilder implements Builder {
private StringBuffer buffer = new StringBuffer();
@Override
public void buildPartOne() {
buffer.append("i am part one\n");
}
@Override
public void buildPartTwo() {
buffer.append("i am part two\n");
}
@Override
public void buildPartThr() {
buffer.append("i am part Thr\n");
}
@Override
public String getResult() {
return buffer.toString();
}
}
Как создавать разные представления?
"определение дожа"
public class Director {
private Builder builder;
public Director(Builder builder) {
this.builder = builder;
}
public void setBuilder(Builder builder) {
this.builder = builder;
}
public void construct() {
builder.buildPartOne();
builder.buildPartTwo();
builder.buildPartThr();
}
}
"имитация вызова"
public class App {
/***
* 建造者模式
* 建造者模式(Builder Pattern)使用多个简单的对象一步一步构建成一个复杂的对象,这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式
*
* 主要解决
* 主要解决在软件系统中,有时候面临着"一个复杂对象"的创建工作,其通常由各个部分的子对象用一定的算法构成;由于需求的变化,这个复杂对象的各个部分经常面临着剧烈的变化,但是将它们组合在一起的算法却相对稳定
*
* 何时使用
* 一些基本部件不会变,而其组合经常变化的时候。
*
* 如何解决
* 将变与不变分离开。
*
* 关键代码
* 建造者:创建和提供实例
* 建造者接口:依赖接口编程
* 指导者:管理建造出来的实例的依赖关系
* 产品:建造者所生产的产品
* 建造者作为参数进入指导者构造方法,通过特定普遍的构造顺序或算法执行,得到产品
*
* 应用实例:
* 1.去肯德基,汉堡、可乐、薯条、炸鸡翅等是不变的,而其组合是经常变化的,生成出所谓的"套餐"
* 2.StringBuilder
*/
public static void main(String[] args){
// 创建建造者接口并指向具体建造者 - 包含最终产品
Builder concreteBuilder = new ConcreteBuilder();
// 创建指导者, 把具体建造者即工人作为参数传入, 通过统一方法执行相应的构建命令
Director director = new Director(concreteBuilder);
director.construct();
// 从工人即具体建造者获取产品
String result = concreteBuilder.getResult();
System.out.println(result);
}
}
Расширенное мышление строителя: связанные вызовы
Связанные вызовы делают код более элегантным~
public class MyBuilder {
// 省略不必要的代码
MyBuilder withName(String name) {
this.setName(name);
return this;
}
MyBuilder withYear(String year) {
this.setYear(year);
return this;
}
MyBuilder withSex(String sex) {
this.setSex(sex);
return this;
}
}
UML-диаграмма
❝Смотрите код ниже~
❞
Модель цепочки ответственности
намерение
Дает нескольким объектам возможность обработать запрос, тем самым избегая связи между отправителем и получателем запроса. Соедините эти объекты вместе и передайте запрос по цепочке, пока объект не обработает его.
типичное приложение
Система ведения журналов Log4J использует идею цепочки ответственности для обработки журналов по уровням путем передачи различных уровней журналов.
Простая реализация системы лог-уровня
"абстрактный класс"
Определите уровень журнала, установите следующий процессор, абстрагируйте метод записи
public abstract class AbstractLogger {
// 责任级别
public static int INFO = 1;
public static int DEBUG = 2;
public static int ERROR = 3;
// 当前级别
int level;
//责任链中的下一个元素
AbstractLogger nextLogger;
public void setNextLogger(AbstractLogger nextLogger){
this.nextLogger = nextLogger;
}
// 记录日志
public void logMessage(int level, String message){
if(this.level <= level){
write(message);
}
if(nextLogger != null){
nextLogger.logMessage(level, message);
}
}
// 抽象方法 -> 重写具体日志输出类型
abstract protected void write(String message);
}
"определенный класс журнала"
public class InfoLoger extends AbstractLogger {
public InfoLoger(int level){
this.level = level;
}
@Override
protected void write(String message) {
System.out.println("InfoLoger Console::Logger: " + message);
}
}
❝Чтобы избежать повторения, покажите только один класс
❞
"фактический вызов"
public class App {
public static void main(String[] args){
AbstractLogger log = getChainOfLoggers();
log.logMessage(AbstractLogger.INFO, "i am info");
log.logMessage(AbstractLogger.DEBUG, "i am debug");
log.logMessage(AbstractLogger.ERROR, "i am error");
}
private static AbstractLogger getChainOfLoggers(){
AbstractLogger error = new ErrorLoger(AbstractLogger.ERROR);
AbstractLogger debug = new DebugLoger(AbstractLogger.DEBUG);
AbstractLogger info = new InfoLoger(AbstractLogger.INFO);
error.setNextLogger(debug);
debug.setNextLogger(info);
return error;
}
}
// 输出结果:
// InfoLoger Console::Logger: i am info
//
// ------------------------
//
// DebugLoger Console::Logger: i am debug
// InfoLoger Console::Logger: i am debug
//
// ------------------------
//
// ErrorLoger Console::Logger: i am error
// DebugLoger Console::Logger: i am error
// InfoLoger Console::Logger: i am error
Суммировать
много форм
- Текущий шаблон аналогичен форме уровня журнала, пока уровень больше, чем A, тогда будут обрабатываться B и C.
- Например, A->B->C выполняется от низкого к высокому уровню, пока он выполняется, он вернется и т. д.
- Самая продвинутая форма: после того, как нижний уровень инициирует запрос, после любой обработки на высоком уровне может быть запрошена обратная связь по запросу (включая асинхронную корреляцию, обмен потоками).
преимущество
- Уменьшить сцепление. Он разделяет отправителя и получателя запроса.
- Объекты упрощены. чтобы объекту не нужно было знать структуру цепочки
- Повышает гибкость при назначении обязанностей объектам, позволяя динамически добавлять или удалять обязанности путем изменения членов цепочки или их переупорядочения.
- Удобно добавлять новые классы обработки запросов
недостаток
- Нет гарантии, что запрос будет получен
- В определенной степени это повлияет на производительность системы, а отлаживать код будет неудобно, что может привести к циклическим вызовам.
- Может быть непросто наблюдать за характеристиками времени выполнения, что затрудняет отладку.
сцены, которые будут использоваться
- Существует несколько объектов, которые могут обрабатывать один и тот же запрос, и какой объект обрабатывает запрос, автоматически определяется средой выполнения.
- Отправить запрос на один из нескольких объектов без явного указания получателя
- Набор объектов может быть динамически указан для обработки запросов.
UML-диаграмма
❝Смотрите код ниже~
❞
режим заметки
намерение
Не нарушая инкапсуляции, зафиксируйте внутреннее состояние объекта и сохраните это состояние вне объекта, чтобы впоследствии объект можно было восстановить в исходное сохраненное состояние.
основной код
"меморандум"
/**
* ******************************
* description: 备忘录,确定数据结构即可
* ******************************
*/
public class Memento {
Map<String, String> data;
}
"Моделирование сценария SMS"
/**
* ******************************
* description: 模拟短信场景
* ******************************
*/
public class MessageData {
private String time;
private String message;
/**
* 存储数据
*/
public Memento saveMemento () {
Map<String, String> map = Maps.newHashMap();
map.put("TIME", time);
map.put("MESSAGE", message);
return new Memento(map);
}
/**
* 取出数据
*/
public void getFromMemento(Memento memento){
time = memento.getData().get("TIME");
message = memento.getData().get("MESSAGE");
}
// 省略部分代码
}
"контейнер для хранения заметок"
public class MementoTaker {
private List<Memento> mementoList = new ArrayList<>();
public void add(Memento state){
mementoList.add(state);
}
public Memento get(int index){
return mementoList.get(index);
}
}
"основной код вызова"
public class App {
public static void main(String[] args) throws InterruptedException {
// 创建备忘录管理者
MementoTaker mementoTaker = new MementoTaker();
MessageData messageData = new MessageData();
messageData.setTime(System.currentTimeMillis() + "");
messageData.setMessage("This is messgae first.");
mementoTaker.add(messageData.saveMemento());
System.out.println("First: -> " + messageData);
Thread.sleep(2000);
messageData.setTime(System.currentTimeMillis() + "");
messageData.setMessage("This is messgae second.");
mementoTaker.add(messageData.saveMemento());
System.out.println("Second: -> " + messageData);
Thread.sleep(2000);
// 回复初次状态
messageData.getFromMemento(mementoTaker.get(0));
System.out.println("********************检测数据是否回到初始状态******************");
System.out.println(messageData);
}
}
Резюме режима: На самом деле этот режим очень прост, то есть определить структуру данных и сохранить копию в контейнере для последующего восстановления, либо повторного использования и т.д.
Суммировать
основное решение
Так называемый режим запоминания предназначен для захвата внутреннего состояния объекта и сохранения состояния вне объекта без разрушения инкапсуляции, чтобы впоследствии объект можно было восстановить в исходное состояние.
Практика меморандумных идей
- сохраняться, играя в игры
- ctri+z в Windows
- управление транзакциями базы данных
UML-диаграмма
Связанные ссылки на код
- С учетом кейсов в двух классических книгах "HeadFirst" и "GOF"
- Предоставляет дружественное руководство по чтению