【23种设计模式笔记】更新到15(单例,工厂,装饰器,适配器,观察者,外观,状态,策略,代理,责任链,模板,享元,命令模式)

23种设计模式

1, 单例模式(创建)

确保一个类只有一个实例, 而且自行实例化并向整个系统提供这个实例

  • 方法修饰符只能是private
  • 构造方法是private, 并且拥有一个当前类的静态成员变量
  • 提供一个静态方法, 向外界提供当前类的实例 (只能再内部实例)

1.1,饿汉式和懒汉式

饿汉式
  • 直接给你实例
//饿汉式
class Singleton{
    private static Singleton singleton = new Singleton();
    private Singleton(){};
    public static Singleton getInstance(){
        return singleton;
    }
}
懒汉式
  • 需要的时候再实例化
//懒汉式   
class Singleton{
    private static Singleton singleton ;
    private Singleton(){};
    //需要添加同步锁, 防止创建多个实例
    public synchronized static Singleton getInstance(){
        if (singleton!=null){
            singleton = new Singleton();
        }
        return singleton;
    }
}

1.2,懒汉式之双重检查锁

//懒汉式  双重检查锁
class Singleton2{
    //使用双重检查锁进行初始化的实例必须使用Volatile关键字修饰
    private volatile static Singleton2 singleton2 ;
    private Singleton2(){};
    //需要添加同步锁, 防止创建多个实例
    public  static Singleton2 getInstance(){
        if (singleton2==null){
            //缩小同步范围, 等于空的时候再判断是否添加锁
            synchronized (Singleton2.class){
                if (singleton2==null){
                    singleton2 = new Singleton2();
                }
            }
        }
        return singleton2;
    }
}
  • 使用volatile关键字修饰 : 禁止指令重排

Singleton2 singleton2 = new Singleton2();可拆分为3个步骤
1,分配内存 ; 2, 初始化对象, 3 指向刚分配的地址, 若发生重排序
假设 A线程执行了1和3, 还没有执行2, B线程来到判断 null, B线程就会直接返回还没有初始化的instance了.
volatile 可以避免重排序

1.3,单例模式出现多个实例情况

单例模式的实例是全局唯一的, 但是在以下两种情况下, 也会出现多个实例
1, 在分布式系统中, 会有多个JVM虚拟机, 各个虚拟机都有一个实例
2, 同一个虚拟机 , 使用了多个类加载器同事加载这个类, 产生多个实例

1.4,注意点

单例模式最佳实践最好是无状态的

如果单例模式有状态的话, 比如他有一个字段 value = 10 , 在A线程改成了20 , 由于只有一个实例
其他地方获取到的也是这个20 ,

单例模式

2,简单工厂模式–不符合开闭原则

简单工厂模式(Simple Factory Pattern): 又称为静态工厂方法(Static Factory Method)模式, 他属于类创建型模式.

在简单工厂模式中, 可以根据参数的不同返回不同的实例.

简单工厂模式专门定义一个类来负责创建其他类的实例, 被创建的实例通常都具有共同的父类.

通常是创建某一大类下面不同类的实例的一种模式

image-20220318202727444

  • 根据参数来创建对应的类

如DateFormat工具类, 获取实例的时候根据传入的参数不同获得不同的子类

image-20220318203057416

例子

/*
简单工厂模式
 */
public class SimpleFactory {
    public  static Product createProduct(String type){
        if (type.equals("A")){
            return new ProductA();
        }else {
            return  new ProductB();
        }
    }

    public static void main(String[] args) {
        Product product = SimpleFactory.createProduct("A");
        product.print();//AAA
    }
}

abstract class Product{
    public abstract void print();
}

class ProductA extends Product{
    @Override
    public void print() {
        System.out.println("AAA");
    }
}
class ProductB extends Product{
    @Override
    public void print() {
        System.out.println("BBB");
    }
}

优点

  • 实现对象的创建和使用分离
    • 创建完全交给专门的工厂去负责
    • 客户端程序员不需要担心创建, 只管使用

缺点

  • 不够灵活, 如果新增一个产品就需要修改工厂,十分麻烦
  • 违反了开闭原则, 没有做到灵活扩展

开闭原则

一个软件实体如类、模块和函数应该对扩展开放,对修改关闭

3, 工厂(方法)模式(创建)

工厂模式中, 之前的核心工厂变成了一个抽象接口 , 它负责给出工厂应该实现的方法, 不在负责所有产品的创建, 而是将具体产品的创建工作交给子类去做, 这样就诞生了具体的子工厂(子类: 负责生产具体的产品对象) , 这样就可以将产品类的实例化操作延迟到工厂子类中去完成, 即通过工厂子类来确定究竟应该实例化哪一个具体实例类

现增加一个产品, 不需要修改工厂类, 而创建一个新的子工厂----扩展优于修改

定义

定义一个用于创建对象的接口, 让子类决定实例化哪个类. 工厂方法使一个类的实例化延迟到其子类

image-20220318215124728

例子

public class Factory {
    public static void main(String [] args) {
        FactoryA factoryA=new FactoryA();
        factoryA.createProduct().print();
        FactoryB factoryB=new FactoryB();
        factoryB.createProduct().print();
    }
}
interface AbstractFactory{
    public Product1 createProduct();
}

class FactoryA implements AbstractFactory{
    @Override
    public Product1 createProduct(){
        return new ProductA();
    }
}
class FactoryB implements AbstractFactory{
    @Override
    public  Product1 createProduct(){
        return new ProductB();
    }
}

abstract class Product1 {
    public abstract void print();
}
class ProductA extends Product1 {
    @Override
    public void print(){
        System.out.println("ProductA正在打印!");
    }
}
class ProductB extends Product1 {
    @Override
    public void print(){
        System.out.println("ProductB正在打印!");
    }
}

4,抽象工厂模式(创建)–不符合开闭原则

  • 工厂模式
    • 新增一个工厂, 需要新增一个对应的工厂类, 每个具体工厂都负责生产一种对应的具体产品
    • 工厂模式要求所有的产品都属于同一大类 (指他们都继承了同一抽象类或实现了同一个接口)
  • 抽象工厂模式
    • 可以生产多个大类的产品

image-20220328232447481

  • 对比工厂模式, 就多了一个大类,
  • 如果只有一个产品体系的话, 就会退化成工厂模式, 相当于工厂模式的拓展
  • 缺点
    • 和简单工厂一样, 增加一个新产品体系, 必须要对工厂类修改, 修改工厂逻辑,包括抽象工厂以及所有具体工厂

例子

//抽象工厂
public interface AbstractFactory {
    Phone createPhone(String param);
    Mask createMask(String param);
}
//具体工厂
class SuperFactory implements AbstractFactory{
    @Override
    public Phone createPhone(String param) {
        return new HwPhone();
    }

    @Override
    public Mask createMask(String param) {
        return new N95();
    }
}

//产品大类:  手机
interface Phone{}
class HwPhone implements Phone{}
//产品大类:  口罩
interface Mask{}
class N95 implements Mask{}

5,装饰器模式

举个栗子:

image-20220328234020456

  • 我有个机器人, 能唱歌对话放音乐

有一天, 这个机器人功能不够用了, 我想要更多的功能, 比如拖地跳舞

方式一: 通知厂家对第一代进行升级修改, 最终研制出了第二代产品

image-20220328234247982

  • 之后厂家卖第二套产品都会有拖地跳舞的功能了
方式二: 自己改造

image-20220328234413916

  • 张三给机器人套了个壳子, 加了胳膊腿, 也实现了拖地和跳舞功能
  • 他灵活的扩展了原有的功能, 而且不需要等待厂家重新研发设计发布
例子小结

这两种方式都可以实现给一个类或对象增加新的功能

  • 第一种称之为继承机制

    • 就是继承一个现有类, 在子类进行扩展功能
  • 第二种称之为关联机制

    • 把一个对象嵌入到另一个对象中, 相当于把机器人嵌入到箱子里来, 给他套一个**壳子**来扩展功能
    • 这个**壳子** 就是我们所说的装饰器 , 所以第二种方式也称之为装饰器模式
  • 区别:

    • 第一种是静态的, 一定要写一个新子类, 对类层级进行扩展
    • 第二种是动态的, 拿到一个对象就可以对其进行扩展, 不需要修改原有的类逻辑

定义:

动态的给一个对象添加一些额外的功能, 就增加功能来说, 装饰器模式比生成子类更加灵活

image-20220328235252937

例子

public class DecoratorPattern {
    public static void main(String[] args) {
        MyRobot myRobot = new MyRobot(new FirstRobot()); //和输入输出流差不多
        myRobot.doSomething();
    }
}
interface Robot {
    public void doSomething();
}

class FirstRobot implements Robot{
    @Override
    public void doSomething() {
        System.out.println("唱歌");
        System.out.println("跳舞");
    }
}

class MyRobot implements Robot{
    private Robot robot;
    public MyRobot (Robot robot){
        this.robot = robot;
    }
    @Override
    public void doSomething() {
        robot.doSomething(); //原有的功能
    }
    public void doElseThing(){ //扩展功能
        robot.doSomething();
        System.out.println("拖地");
        System.out.println("洗碗");
    }
}

输入输出流使用了装饰器模式

image-20220329000855815

6,适配器模式

定义:

  • 将一个类的接口变换成客户端锁期待的另一种接口, 从而使原本因接口不匹配而无法在一起工作的两个类能够在一起工作

适配器模式类图

  • 和装饰器模式的区别
    • 适配器实现接口,接口方法是对原来类的变化,也就是适配
    • 和装饰器模式一个区别 是 装饰器模式和扩展类继承了同一个接口

例子

public class AdapterPattern {
    public static void main(String[] args) {
        String translate = new Adapter(new Speaker()).translate();
        System.out.println(translate);//翻译: 我爱你
    }
}
class Speaker{
    public String speak(){
        return "我爱你";
    }
}
//翻译
interface Translator{
    String translate();
}
class Adapter implements Translator{
    //把需要适配的对象传入
    private Speaker speaker;

    public Adapter(Speaker speaker) {
        this.speaker = speaker;
    }

    @Override
    public String translate() {
        String speak = speaker.speak();
        //....做了一些事 比如翻译
        return "翻译: "+speak;
    }
}

7,观察者模式

image-20220329221719790

  • 张三欠了赵四等人一笔钱,
  • 张三是一个讲信用的人
  • 张三一旦有钱了就回去通知各位债主子还钱
  • 张三和债主子之间的依赖关系, 在设计模式中 被称为观察者模式
  • 发布订阅模式
    • 观察者和目标相互知道,而发布者和订阅者不用互相知道

定义:

观察者模式: 定义对象间的一种一对多依赖关系, 使得每当一个对象状态发生改变时, 其相关依赖对象皆能得到通知并被自动更新

例子

import java.util.ArrayList;

public class Observe{
    public static void main(String[] args) {
        ZhangSan zhangSan = new ZhangSan();
        zhangSan.borrow(new Lisi());
        zhangSan.borrow(new WangEr());
        //state状态改变,  由张三决定
        zhangSan.notifyCreated();
    }
}
//借款方
interface Debit {
    //借钱方法
    void borrow(Credit credit);
    //通知还钱的方法
    void notifyCreated();
}

class ZhangSan implements Debit{
    ArrayList<Credit> credits = new ArrayList<>();
    int state = 1;
    @Override
    public void borrow(Credit credit) {
        credits.add(credit);//添加一个观察者对象
    }

    @Override
    public void notifyCreated() {
            credits.forEach(credit -> credit.takeMoney());
    }
}
//要款方
interface Credit{
    void takeMoney();
}

class Lisi implements Credit{

    @Override
    public void takeMoney() {
        System.out.println("l李四来要钱了");
    }
}

class WangEr implements Credit{

    @Override
    public void takeMoney() {
        System.out.println("l王二来要钱了");

    }
}

image-20220329222739643

image-20220329222842737

8,外观模式–不符合开闭原则

image-20220329223728908

  • 张三经历了一些事情, 想证明自己活着, 需要开四项证明

image-20220329223958396

  • 后面张三变成了给别人开证明的工作人员
  • 赵四想证明自己或者, 只需要找张三开证明就可以了, 张三去给完成四个证明的过程
  • 这个例子类似外观模式, 通过给现有的系统添加一个新接口, 去隐藏掉复杂性

定义:

要求一个子系统的外部与其内部的通信必须通过一个统一的对象进行

外观模式提供一个高层次的接口, 使得子系统更易使用

**缺点: **

  • 不符合开闭原则, 如果子系统扩展的话, 必须修改外观模式的类

image-20220329224404828

例子

public class FacadePattern {
    public static void main(String[] args) {
        //调用者只需要使用外观类来完成四项证明, 不需要关心内部流程
        new Facade().prove();
    }
}
//如四个证明
class SubFlow1{
    boolean isTrue(){return true;}
}
class SubFlow2{
    boolean isTrue(){return true;}
}
class SubFlow3{
    boolean isTrue(){return true;}
}
class SubFlow4{
    boolean isTrue(){return true;}
}
//由外观类完成
class   Facade{
    SubFlow1 s1 =  new SubFlow1();
    SubFlow2 s2 =  new SubFlow2();
    SubFlow3 s3 =  new SubFlow3();
    SubFlow4 s4 =  new SubFlow4();
    boolean prove(){
        return s1.isTrue()&&s2.isTrue()&&s3.isTrue()&&s4.isTrue();
    }
}

9,状态模式

阿里巴巴开发手册中提到了表达异常分支时,少用if-else 方式

image-20220329225348450

  • 卫语句: 在使用分支的时候 , 可以提前范围, 比如下面的isBusy中, 满足了直接返回

定义

允许一个对象在其内部状态改变时改变他的行为, 对象看起来似乎修改了他的类.

其别名为状态对象, 状态模式是一种对象行为型模式

  • 行为和状态是一一对应的
  • 不同的状态关联了不同的行为

image-20220329225823070

  • 优点
    • 封装了转换规则, 并枚举了可能的状态
    • 把所有的状态有关的行为封装到状态类中, 并且可以方便的扩展新的状态
    • 还可以让多个环境对象共享一个状态对象, 从而减少对象的创建
  • 缺点
    • 会增加系统(状态)类, 和(状态) 对象的个数, 使用不当会导致程序结构或代码的混乱
public class StatePattern {
    public static void main(String[] args) {
        Context ZhangSan = new Context();
        ZhangSan.changeState(new Angry());//修改状态为Angry
        ZhangSan.work();//小yz跑了, 无精打采!
        ZhangSan.changeState(new Happy());//小yz回来了
        ZhangSan.work();//干活有劲! 一个顶俩!

    }
}
//状态
abstract class State{
    abstract void doWork();
}
//几种状态
class Happy extends State{
    @Override
    void doWork() {
        System.out.println("干活有劲! 一个顶俩!");
    }
}
class Angry extends State{
    @Override
    void doWork() {
        System.out.println("小yz跑了, 无精打采!");
    }
}
class Sad extends State{
    @Override
    void doWork() {
        System.out.println("不开心, 啥也不干! ");
        return;
    }
}
class Context{
    //传入状态
    private State state;
    public void changeState(State state) {
        this.state = state;
    }
    public void work(){
        state.doWork();
    }
}

10,策略模式

image-20220329231412633

  • 比如洗衣机有不同的洗衣模式, 我们使用的过程中只需要选择对应的策略, 洗衣机就会根据这个策略去完成操作

定义

定义一组算法, 将每个算法都封装起来, 并且使他们之间可以互换.

策略模式让算法独立于使用他的客户而变化, 也称之为政策模式

image-20220329231733428

  • 状态模式:
    • 状态强调的状态的不同,状态不同,要做的事情不同(开心->犒劳犒劳自己,不开心->请假不上班),聚焦在开心或者不开心上,而开心或者不开心具体要做什么不关心,你不开心明天辞职也可以
    • 状态可以是外部来改变状态, 也可以自己来更改状态
  • 策略模式:
    • 策略强调要做的事情不同会导致做事情的具体步骤不同,强调的是“做的步骤”,即行为、算法本身

例子:

jdk中有一个线程池执行器

image-20220329233326656

  • 创建的时候需要传入一个拒绝执行策略

image-20220329233415230

  • 这四种需要在客户端传入的, 构造方法的时候需要传入, 通过传入的策略来执行不同的逻辑

11, 代理模式

image-20220329233644212

  • 张三是一个世外高手, 只有代理人能见到张三

  • 翠花想送一包中华给张三, 只能通过代理人传达给张三

  • 张三和代理人之间构成一种代理关系, 而翠花通过代理人传访问张三这种行为关系称之为代理模式

  • 代理人控制了张三的访问

另一个栗子:

比如说我们想访问一个类, 而这个类在另外一台服务器上,

这时我们可以创建一个代理对象, 代理对象来建立连接, 远程调用另一台服务器的实现类,最后把实现类返回给我们

定义:

为其他对象提供一种代理, 以控制对这个对象的访问

image-20220329234306806

package mode11_ProxyPattern;

/**
 * 代理模式
 */
public class ProxyPattern {
    public static void main(String[] args) {
        new RealSubjectProxy().doWork();
    }
}
//目标类接口
interface Subject{
    void doWork();
}
//真正目标类
class RealSubject implements Subject{
    @Override
    public void doWork() {

    }
}
//代理类
class RealSubjectProxy implements Subject{
    private RealSubject subject;

    public RealSubjectProxy() {
        try {
            //通过类加载器获取
            this.subject = (RealSubject) this.getClass().getClassLoader().loadClass("mode11_ProxyPattern.RealSubject").newInstance();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    //可以在代理类中添加一些方法
    public void connect(){
        System.out.println("建立连接");
    }
    public void log(){
        System.out.println("日志记录");
    }
    @Override
    public void doWork() {
        connect();
        subject.doWork();
        log();
    }
}
  • 发现代理模式跟装饰器模式差不多
  • 代理模式
    • 侧重于对代理对象的访问
  • 装饰器模式
    • 侧重于对对象的功能扩展

12,责任链模式

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-9dsDxhzm-1648712013536)(…/设计模式/https://gitee.com/xbd_zc/images/raw/master/img/image-20220330132042989.png)]

  • 比如张三想请假
  • 找开发经理, 开发经理可以处理一天以内的假期, 超过需由部门经理处理
  • 部门经理可以处理一周内的假期, 超过需由总经理处理
  • 开发经理, 部门经理, 总经理形成了一条审批链, 每个人负责处理自己能力范围的事,超出交给下一个人
  • 对张三来说:
    • 不需要关系审批的流程, 只需要吧请假单交给开发经理,等待结果即可
  • 对于审批者来说
    • 只关心自己职责范围内的请求, 超出的请求交给下一个审批者进行审核
  • 张三请假领导审批这个流程,设计模式中称之为责任链模式

定义:

责任链模式是一种处理请求的模式, 他让多个处理器都有机会处理该请求, 直到其中某个处理成功为止.

责任链模式把多个处理器串成链, 然后让请求在链上传递

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-6Fesd0Qs-1648712013536)(…/设计模式/https://gitee.com/xbd_zc/images/raw/master/img/image-20220330133814633.png)]

例子

package mode12_ChainRespPattern;

public class ChainRespPattern {
    public static void main(String[] args) {
        Handler lev1 = new Leader();
        Handler lev2 = new Boss();
        lev1.setNextHandler(lev2);

        lev1.process(10);//Leader 处理了
        lev1.process(11);//Boss 处理了
    }
}
//抽象处理类
abstract class Handler{
    //需要连接到下一个处理类
    protected Handler nextHandler;
    public void setNextHandler(Handler nextHandler){
        this.nextHandler = nextHandler;
    }
    //当前消息
    public abstract void process(Integer info);
}
//处理1-10级的请求
class Leader extends Handler{

    @Override
    public void process(Integer info) {
        if (info > 0 && info < 11) {
            System.out.println("Leader 处理了");
        }else {
            nextHandler.process(info);
        }
    }
}
//Boss
class Boss extends Handler{

    @Override
    public void process(Integer info) {
       System.out.println("Boss 处理了");
    }
}

优点和缺点

优点

  • 将请求和处理分开, 请求者不需要知道怎么处理, 处理者不需要知道处理的全貌
  • 可以提高处理系统灵活性, 如新增一个处理器到链条中代价比较小的

缺点

  • 降低系统性能, 每个请求需要从链头走到链尾
  • 不易于调试

13,模板方法模式

定义:

定义了一个操作中的算法的框架, 而将一些步骤延迟到子类中, 使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤

image-20220330214103611

例子

package mode13_TemplateMethodPattern;

public class TemplateMethodPattern {
    public static void main(String[] args) {
        Cooking cookingFood = new CookingFood();
        cookingFood.cook();
    }
}
abstract class Cooking{
    protected  abstract void step1();
    protected  abstract void step2();
    public void  cook(){
        System.out.println("开始做饭"); //父类可以把不变的步骤先加入
        step1();//可变步骤交给子类去实现
        step2();
        System.out.println("做饭完成");
    }
}
class CookingFood extends Cooking{
    @Override
    protected void step1() {
        System.out.println("第一步:  洗菜");
    }

    @Override
    protected void step2() {
        System.out.println("第二步:  丢进锅里炒");
    }
}

14,享元模式

享元: 共享, 如共享单车

image-20220330215424437

  • 张三上传了一个文件到网盘, 分享给赵四也存了一份, 这不代表网盘就有两份相同的资源, 可能是同一份资源
  • 只是创建时间, 和拥有者属性不同

定义

享元模式: 运用共享技术 有效的支持大量细类度的对象

  • 最典型的的应用就是池技术

image-20220330215844890

例子

package mode14_Flyweight;

import java.util.HashSet;
import java.util.Set;

/**
 * 共享单车抽象享元类
 */
abstract class BikeFlyWeight {
    //内部状态
    protected Integer state = 0; //0 是未使用, 1是使用中

    //使用者外部状态
    abstract void ride(String userName);//存入骑车人
    abstract void back();//归还单车
    public Integer getState(){
        return state;
    }
}

/**
 * 具体享元类
 */
class MoBikeFlyWeight extends BikeFlyWeight{
    //定义新的内部状态, 车架号
    private String bikeId;
    public MoBikeFlyWeight(String bikeId) {
        this.bikeId = bikeId;
    }
    @Override
    void ride(String userName) {
        state = 1;
        System.out.println(userName+"骑车启动了, 车号:"+bikeId);
    }
    @Override
    void back() {
        state = 0;
    }
}
/**
 * 享元工厂, 用来管理
 * 定义为单例模式
 */
class BikeFlyWeightFactory{
    private static BikeFlyWeightFactory instance = new BikeFlyWeightFactory();
    private Set<BikeFlyWeight> pool = new HashSet<>();
    public static BikeFlyWeightFactory getInstance(){
        return instance;
    }
    private BikeFlyWeightFactory(){//定义共享单车池
        for (int i = 0; i < 2; i++) {
            pool.add(new MoBikeFlyWeight(i+"号"));
        }
    }
    //获取一辆单车
    public BikeFlyWeight getBike(){
        for (BikeFlyWeight bike : pool)
            if (bike.getState() == 0)
                return bike;
        return null;
    }
}
public class FlyWeightPattern{
    public static void main(String[] args) {
        BikeFlyWeight bike1 = BikeFlyWeightFactory.getInstance().getBike();
        bike1.ride("张三");//张三骑车启动了, 车号:1号
//        bike1.back();//1号车没归还

        BikeFlyWeight bike2 = BikeFlyWeightFactory.getInstance().getBike();
        bike2.ride("王二");//王二骑车启动了, 车号:0号
        bike2.back();

        BikeFlyWeight bike3 = BikeFlyWeightFactory.getInstance().getBike();
        bike3.ride("李四");//李四骑车启动了, 车号:0号
        bike3.back();

        System.out.println(bike1 == bike2);//false
        System.out.println(bike2 == bike3);//true
    }
}

优点:

  • 通过池技术, 极大减少了内存中的对象数量, 使相同对象在内存中只保留一份
  • 通过内部状态和外部状态的相互分离, 使得可以在不同对象中实现共享

缺点:

  • 需要分离出内外状态,所以程序逻辑相对较复杂
  • 外部状态都需要客户端进行传入, 也会影响运行时间

15,命令模式(行为)

image-20220330224521082

  • 比如我们在开发一款文字编辑器,当前任务是创建一个工具栏, 工具栏包含了许多按钮, 如删除,打印等
  • 这时我们创建一个按钮类, 可以用于工具栏的按钮, 也可以做一个普通按钮, 也可以做对话框的按钮

image-20220330224754112

  • 每个按钮都长得差不多, 但是都有各自的操作逻辑, 那我们在什么地方存放他的操作逻辑呢
  • 最简单的方式是继承button按钮, 在子类中写业务逻辑, 非常简单, 缺陷也很大, 我们去修改基类按钮,所有子类都需要对应修改
  • 而button按钮是一个图形按钮, 如果把业务逻辑也绑定在上面的话, 他既要渲染也要实现业务, 就无法复用了

image-20220330225208658

  • 这里我们可以将图形界面和业务逻辑进行分层
  • 用户界面点击了按钮或使用快捷键后会提交一个请求, 到业务逻辑这边进行处理
  • 而命令模式, 建议我们不直接提交请求, 而是将请求封装起来,组成一个命令类

image-20220330225517105

  • 命令对象可以连接不同的图形对象和业务逻辑对象
  • 命令对象中会包含所有请求的细节 , 比如调用的对象,方法名, 参数列表…
  • 这时,所有的图形对象只需要触发对应命令即可, 命令对象会去处理所有的细节工作

image-20220330225840428

  • 定义一个接口或抽象类, 让所有的命令去实现这个接口,来实现面向接口开发
  • 而按钮(button)或快捷键(Shortcut)可以触发Command的execute()方法
  • 可以简单理解为分层结构中的一个中间层, 充当一个中间人

定义:

命令模式是一种行为设计模式, 他可将请求转换为一个包含与请求相关的所有信息的独立对象

该转换让你能根据不同的请求方法参数话, 延迟请求执行或将其放入队列中, 且能实现可撤销操作

  • 该转换把命令封装成一个对象, 可以将对象放入一个队列中, 队列中依次执行, 可以理解为一个命令的执行队列
  • 一个队列放几十个命令, 我可以按顺序执行,延期执行,也可以实现可撤销操作

例子

package mode15_CommandPattern;

/**
 * 命令接口
 */
interface Command{
    void execute();
}
/**
 * GUI层 保存按钮
 */
class SaveButton{
    private Command command;
    /*
    ............此处省略一些渲染的逻辑
     */
    public void bindCommand(Command command){ //绑定命令
        this.command = command;
    }
    public void doPrint(){
        if (command == null) {
            throw new RuntimeException("设备初始化失败!");
        }
        command.execute();
    }
}
/**
 * 业务逻辑层:  打印服务
 */
class PrintService{
    public void print(String text){
        System.out.println(text);
    }
}
/**
 * 文本编辑器的文本框
 */
class TextBox{
    private String context;

    public void setContext(String context) {
        this.context = context;
    }

    public  String getContext(){
        return context;
    }
}
/**
 * 具体命令, 打印命令
 */
class PrintCommand implements Command{
    private PrintService printService = new PrintService();
    private TextBox box;//文本框, 打印内容

    public PrintCommand(TextBox box) {
        this.box = box;

    }
    @Override
    public void execute() {
        printService.print(box.getContext());//调用打印方法
    }
}

public class CommandPattern {
    public static void main(String[] args) {
        SaveButton saveButton = new SaveButton();
        TextBox box = new TextBox();

        PrintCommand printCommand = new PrintCommand(box);
        saveButton.bindCommand(printCommand);

        box.setContext("ABCDEFG");
        saveButton.doPrint();

        box.setContext("HIJKLMN");
        saveButton.doPrint();
    }
}

16,生成器模式(创建)

学习地址(B站子烁)

https://www.bilibili.com/video/BV15V411z7nD

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值