前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >【一起学系列】之剩下的设计模式们

【一起学系列】之剩下的设计模式们

作者头像
Kerwin
发布2020-07-30 11:38:50
3050
发布2020-07-30 11:38:50
举报
文章被收录于专栏:是Kerwin啊是Kerwin啊

前言

【开发】:老大,你教了我挺多设计模式的,已经全部教完了吗?

【BOSS】:没呢,还有好几个设计模式没说过呢,今天再传授你三个吧,分别是建造者模式,责任链模式,备忘录模式,如何?

【开发】:好啊,我最喜欢学习了!

建造者模式

意图

将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。

核心代码

「定义建造接口」

代码语言:javascript
复制
public interface Builder {

    void buildPartOne();

    void buildPartTwo();

    void buildPartThr();

    /***
     * 一般情况肯定是一个复杂的对象
     */
    String getResult();
}

「定义实际建造工人」

代码语言:javascript
复制
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();
    }
}

如何创建不同的表示?

「定义督公」

代码语言:javascript
复制
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();
    }
}

「模拟调用」

代码语言:javascript
复制
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);
    }
}

建造者的延展思考:链式调用

链式调用让代码更优雅~

代码语言:javascript
复制
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 日志系统即是使用了责任链的思想,通过不同日志级别的传递,按级别处理日志

简单实现一个Log等级系统

「抽象类」

定义日志等级,设置下一个处理器,抽象出写入方法

代码语言:javascript
复制
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);
}

「具体日志类」

代码语言:javascript
复制
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);
    }
}

❝为了避免重复,只展示一个类 ❞

「实际调用」

代码语言:javascript
复制
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

总结

多种形式
  • 当前pattern下类似日志级别形式, 只要等级比A大,那B,C都会处理
  • 如A->B->C 由低到高级别执行,只要执行就返回等
  • 最高级形式: 低级发起请求后, 高级任一处理后,请求反馈即可(涉及到异步相关,线程通信)
优点
  • 降低耦合度。它将请求的发送者和接收者解耦
  • 简化了对象。使得对象不需要知道链的结构
  • 增强给对象指派职责的灵活性,通过改变链内的成员或者调动它们的次序,允许动态地新增或者删除责任
  • 增加新的请求处理类很方便
缺点
  • 不能保证请求一定被接收
  • 系统性能将受到一定影响,而且在进行代码调试时不太方便,可能会造成循环调用
  • 可能不容易观察运行时的特征,有碍于除错
使用场景
  • 有多个对象可以处理同一个请求,具体哪个对象处理该请求由运行时刻自动确定
  • 在不明确指定接收者的情况下,向多个对象中的一个提交一个请求
  • 可动态指定一组对象处理请求

UML图

❝代码见下方~ ❞

备忘录模式

意图

在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态,这样以后可将对象恢复到原先保存的状态

核心代码

「备忘录」

代码语言:javascript
复制
/**
 * ******************************
 * description:  备忘录,确定数据结构即可
 * ******************************
 */
public class Memento {
    Map<String, String> data;
}

「模拟短信场景」

代码语言:javascript
复制
/**
 * ******************************
 * 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");
    }

    // 省略部分代码
}

「备忘录存储容器」

代码语言:javascript
复制
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);
    }
}

「核心调用代码」

代码语言:javascript
复制
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);
    }
}

模式总结:其实该模式非常简单,即确定好数据结构在容器中存储一份,以便后续恢复,或者重新使用等等

总结

主要解决

所谓备忘录模式就是在不破坏封装的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态,这样可以在以后将对象恢复到原先保存的状态

备忘录思想的实践
  • 打游戏时的存档
  • Windows 里的 ctri + z
  • 数据库的事务管理

UML图

相关代码链接

GitHub地址:https://github.com/kkzhilu/Kerwin-DesignPattern

  • 兼顾了《HeadFirst》以及《GOF》两本经典书籍中的案例
  • 提供了友好的阅读指导
本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2020-07-03,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 是Kerwin啊 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 前言
  • 建造者模式
    • 意图
      • 核心代码
        • 如何创建不同的表示?
          • 建造者的延展思考:链式调用
            • UML图
            • 责任链模式
              • 意图
                • 典型应用
                  • 简单实现一个Log等级系统
                    • 总结
                      • 多种形式
                      • 优点
                      • 缺点
                      • 使用场景
                    • UML图
                    • 备忘录模式
                      • 意图
                        • 核心代码
                          • 总结
                            • 主要解决
                            • 备忘录思想的实践
                          • UML图
                          • 相关代码链接
                          相关产品与服务
                          容器服务
                          腾讯云容器服务(Tencent Kubernetes Engine, TKE)基于原生 kubernetes 提供以容器为核心的、高度可扩展的高性能容器管理服务,覆盖 Serverless、边缘计算、分布式云等多种业务部署场景,业内首创单个集群兼容多种计算节点的容器资源管理模式。同时产品作为云原生 Finops 领先布道者,主导开源项目Crane,全面助力客户实现资源优化、成本控制。
                          领券
                          问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档