【开发】:老大,你教了我挺多设计模式的,已经全部教完了吗?
【BOSS】:没呢,还有好几个设计模式没说过呢,今天再传授你三个吧,分别是建造者模式,责任链模式,备忘录模式,如何?
【开发】:好啊,我最喜欢学习了!
将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。
「定义建造接口」
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; } } 复制代码
❝代码见下方~
❞
使多个对象都有机会处理请求,从而避免请求的发送者和接收者之间的耦合关系。将这些对象连城一条链,并沿着这条链传递该请求,直到有一个对象处理它为止
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 复制代码
❝代码见下方~
❞
在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态,这样以后可将对象恢复到原先保存的状态
「备忘录」
/** * ****************************** * description: 备忘录,确定数据结构即可 * ****************************** */ public class Memento { Map<String, String> data; } 复制代码
「模拟短信场景」
/** * ****************************** * 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); } } 复制代码
模式总结:其实该模式非常简单,即确定好数据结构在容器中存储一份,以便后续恢复,或者重新使用等等
所谓备忘录模式就是在不破坏封装的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态,这样可以在以后将对象恢复到原先保存的状态
GitHub地址