设计原则与设计模式

什么是设计原则?

1. 单一职责原则(SRP) 

定义:就一个类而言,应该仅有一个引起它变化的原因。 
从这句定义我们很难理解它的含义,通俗讲就是我们不要让一个类承担过多的职责。如果一个类承担的职责过多,就等于把这些职责耦合在一起,一个职责的变化可能会削弱或者抑制这个类完成其他职责的能力。这种耦合会导致脆弱的设计,当变化发生时,设计会遭受到破坏。 
比如我经常看到一些Android开发在Activity中写Bean文件,网络数据处理,如果有列表的话Adapter 也写在Activity中,问他们为什么除了好找也没啥理由了,把他们拆分到其他类岂不是更好找,如果Activity过于臃肿行数过多,显然不是好事,如果我们要修改Bean文件,网络处理和Adapter都需要上这个Activity来修改,就会导致引起这个Activity变化的原因太多,我们在版本维护时也会比较头疼。也就严重违背了定义“就一个类而言,应该仅有一个引起它变化的原因”。 
当然如果想争论的话,这个模式是可以引起很多争论的,但请记住一点,你写代码不只是为了你也是为了其他人。
2. 开放封闭原则(ASD) 
定义:类、模块、函数等等等应该是可以拓展的,但是不可修改。 
开放封闭有两个含义,一个是对于拓展是开放的,另一个是对于修改是封闭的。对于开发来说需求肯定是要变化的,但是新需求一来,我们就要把类重新改一遍这显然是令人头疼的,所以我们设计程序时面对需求的改变要尽可能的保证相对的稳定,尽量用新代码实现拓展来修改需求,而不是通过修改原有的代码来实现。 
假设我们要实现一个列表,一开始只有查询的功能,如果产品又要增加添加功能,过几天又要增加删除功能,大多数人的做法是写个方法然后通过传入不同的值来控制方法来实现不同的功能,但是如果又要新增功能我们还得修改我们的方法。用开发封闭原则解决就是增加一个抽象的功能类,让增加和删除和查询的作为这个抽象功能类的子类,这样如果我们再添加功能,你会发现我们不需要修改原有的类,只需要添加一个功能类的子类实现功能类的方法就可以了。

3.里氏替换原则(LSP) 
定义:所有引用基类(父类)的地方必须能透明地使用其子类的对象 
里氏代换原则告诉我们,在软件中将一个基类对象替换成它的子类对象,程序将不会产生任何错误和异常,反过来则不成立,如果一个软件实体使用的是一个子类对象的话,那么它不一定能够使用基类对象。 
里氏代换原则是实现开闭原则的重要方式之一,由于使用基类对象的地方都可以使用子类对象,因此在程序中尽量使用基类类型来对对象进行定义,而在运行时再确定其子类类型,用子类对象来替换父类对象。 
在使用里氏代换原则时需要注意如下几个问题:

子类的所有方法必须在父类中声明,或子类必须实现父类中声明的所有方法。根据里氏代换原则,为了保证系统的扩展性,在程序中通常使用父类来进行定义,如果一个方法只存在子类中,在父类中不提供相应的声明,则无法在以父类定义的对象中使用该方法。
我们在运用里氏代换原则时,尽量把父类设计为抽象类或者接口,让子类继承父类或实现父接口,并实现在父类中声明的方法,运行时,子类实例替换父类实例,我们可以很方便地扩展系统的功能,同时无须修改原有子类的代码,增加新的功能可以通过增加一个新的子类来实现。里氏代换原则是开闭原则的具体实现手段之一。
Java语言中,在编译阶段,Java编译器会检查一个程序是否符合里氏代换原则,这是一个与实现无关的、纯语法意义上的检查,但Java编译器的检查是有局限的。
4.依赖倒置原则(DIP) 
定义:高层模块不应该依赖低层模块,两个都应该依赖于抽象。抽象不应该依赖于细节,细节应该依赖于抽象。 
在Java中,抽象就是指接口或者抽象类,两者都是不能直接被实例化的;细节就是实现类,实现接口或者继承抽象类而产生的就是细节,也就是可以加上一个关键字new产生的对象。高层模块就是调用端,低层模块就是具体实现类。 
依赖倒置原则在Java中的表现就是:模块间通过抽象发生,实现类之间不发生直接依赖关系,其依赖关系是通过接口或者抽象类产生的。如果类与类直接依赖细节,那么就会直接耦合,那么当修改时,就会同时修改依赖者代码,这样限制了可扩展性。

5.迪米特原则(LOD) 
定义:一个软件实体应当尽可能少地与其他实体发生相互作用。 
也称为最少知识原则。如果一个系统符合迪米特法则,那么当其中某一个模块发生修改时,就会尽量少地影响其他模块,扩展会相对容易,这是对软件实体之间通信的限制,迪米特法则要求限制软件实体之间通信的宽度和深度。迪米特法则可降低系统的耦合度,使类与类之间保持松散的耦合关系。 
迪米特法则要求我们在设计系统时,应该尽量减少对象之间的交互,如果两个对象之间不必彼此直接通信,那么这两个对象就不应当发生任何直接的相互作用,如果其中的一个对象需要调用另一个对象的某一个方法的话,可以通过第三者转发这个调用。简言之,就是通过引入一个合理的第三者来降低现有对象之间的耦合度。 
在将迪米特法则运用到系统设计中时,要注意下面的几点:在类的划分上,应当尽量创建松耦合的类,类之间的耦合度越低,就越有利于复用,一个处在松耦合中的类一旦被修改,不会对关联的类造成太大波及;在类的结构设计上,每一个类都应当尽量降低其成员变量和成员函数的访问权限;在类的设计上,只要有可能,一个类型应当设计成不变类;在对其他类的引用上,一个对象对其他对象的引用应当降到最低。

6.接口隔离原则(ISP) 
定义:一个类对另一个类的依赖应该建立在最小的接口上。 
建立单一接口,不要建立庞大臃肿的接口,尽量细化接口,接口中的方法尽量少。也就是说,我们要为各个类建立专用的接口,而不要试图去建立一个很庞大的接口供所有依赖它的类去调用。 
采用接口隔离原则对接口进行约束时,要注意以下几点:

接口尽量小,但是要有限度。对接口进行细化可以提高程序设计灵活性,但是如果过小,则会造成接口数量过多,使设计复杂化。所以一定要适度。
为依赖接口的类定制服务,只暴露给调用的类它需要的方法,它不需要的方法则隐藏起来。只有专注地为一个模块提供定制服务,才能建立最小的依赖关系。
提高内聚,减少对外交互。使接口用最少的方法去完成最多的事情。

什么是设计模式?

通俗来讲,设计模式就是针对某一种特殊场景而给出的标准解决方案,它是前辈们的经验性总结,也是实现软件工程化的基础,良好的设计模式应用 可以是我们的软件变得更加健壮可维护。

设计模式按照类型划分可以分为三大类,如下所示:

创建型设计模式:如同它的名字那样,它是用来解耦对象的实例化过程。
结构型设计模式:将类和对象按照一定规则组合成一个更加强大的结构体。
行为型设计模式:定义类和对象的交互行为。
23种设计模式划分如下图所示:

 注:23种设计模式很多小伙伴都烂熟于心,但是真正编程实践的时候未必会想的起来,这其实是一个潜移默化的过程,在看设计模式的时候,尽量多动手写一写,其中 手写(不借助IDE)的效果最佳,可以加深理解,理解的深了,编程的时候自然就可以想的到去应用。

一 创建型设计模式
创建型设计模式主要用来解耦对象的实例化过程,控制实例的生成。

创建型设计模式一共有六种,如下所示:

1.1 单例模式
模式定义

当系统中只需要一个实例或者一个全局访问点的时候可以使用单例模式。

优点:节省系统创建对象的资源,提高了系统效率,提供了统一的访问入口,可以严格控制用户对该对象的访问。
缺点:只有一个对象,积累的职责过重,违背了单一职责原则。构造方法为private,无法继承,扩展性较差。
单例模式的实现由很多种,如下所示:

懒汉式单例
双层校验锁单例
容器单例
静态内部类单例
枚举单例
其中静态内部类单例和枚举单例都是单例模式最佳的实现,但是出于便利性的考量,双层校验锁的实现应用的更为广泛,如下所示:

public class DoubleCheckSingleton {
    
    // volatile关键字保证了:① instance实例对于所有线程都是可见的 ② 禁止了instance 
    // 操作指令重排序。
    private volatile static DoubleCheckSingleton instance;

    private DoubleCheckSingleton() {
    }

    public static DoubleCheckSingleton getInstance() {
        // 第一次校验,防止不必要的同步。
        if (instance == null) {
            // synchronized关键字加锁,保证每次只有一个线程执行对象初始化操作
            synchronized (DoubleCheckSingleton.class) {
                // 第二次校验,进行判空,如果为空则执行初始化
                if(instance == null){
                     instance = new DoubleCheckSingleton();
                }
            }
        }
        return instance;
    }
}
关于双层校验锁单例为何能实现JVM单例,它的要点在于两次判空和synchronized、volatile关键字,具体原理已经写在上方的注释里,这里 我们单独说一下volatile关键字。

说明我们说到,volatile关键字禁止了instance 操作指令重排序,我们来解释一下,我们知道instance = new DoubleCheckSingleton()这个操作 在汇编指令里大致会做三件事情:

给我们知道instance分配内存。
调用DoubleCheckSingleton()构造方法。
将构造的对象赋值给instance。
但是在真正执行的时候,Java编译器是允许指令乱序执行的(编译优化),所以上述3步的顺序得不到保证,有可能是132,试想一下,如果线程A没有执行第2步,先执行了 第3步,而恰在此时,线程B取走了instance对象,在使用instance对象时就会有问题,双层校验锁单例失败,而volatile关键字可以禁止指令重排序从而解决这个问题。

单例模式的另一个问题就是多进程的情况下的失败问题,因为JVN里的单例是基于一个虚拟机进程的,这个时候通常的做法就是让这个单例支持跨进程调用,这个在 Android里一般用AIDL实现。

1.2 建造者模式
模式定义

封装一个复杂对象的构建过程,可以按照流程来构建对象。

优点:它可以将一个复杂对象的构建与表示相分离,同一个构建过程,可以构成出不同的产品,简化了投建逻辑。
缺点:如果构建流程特别复杂,就是导致这个构建系统过于庞大,不利于控制。
建造者模式的实现,也十分简单,如下所示:

public class Product {

    private String board;
    private String display;
    private String os;

    public String getBoard() {
        return board;
    }

    public String getDisplay() {
        return display;
    }

    public String getOs() {
        return os;
    }

    private Product(Builder builder) {
        // 进行构建
        this.board = builder.board;
        this.display = builder.display;
        this.os = builder.os;
    }

    public static class Builder {
        // 建造者模式还可以设置默认值
        private String board = "default value";
        private String display = "default value";
        private String os = "default value";

        public void setBoard(String board) {
            this.board = board;
        }

        public void setDisplay(String display) {
            this.display = display;
        }

        public void setOs(String os) {
            this.os = os;
        }


        public Product build() {
            return new Product(this);
        }
    }
}
1.3 原型模式
模式定义

当某个对象的数据结构或者构建过程特别复杂,频繁的构建势必会消耗系统性能,这个时候我们采用原型模式对原有的 对象进行克隆,构建新的对象。

优点:直接克隆原有实例生成新的实例,免去了复杂的构建过程,节省了系统资源。
缺点:
实现原型模式也很简单,主需要声明实现loneable接口,然后覆写Object的clone()方法接口。

public class Person implements Cloneable{

    public int age;
    public String name;

    @Override
    public Person clone() throws CloneNotSupportedException {
        return (Person) super.clone();
    }
}
原型模式要注意深拷贝和浅拷贝的问题,Object的clone()方法默认是钱拷贝,即对于引用对象拷贝的地址而不是值,所以要实现 深拷贝,在clone()方法里对于引用对象也有调用一下clone()方法,并且引用对象也要实现Cloneable接口和覆写clone()方法。

接下来我们继续看看三种工厂模式,如下所示:

简单工厂模式:根据传入的参数决定实例化哪个对象。
工厂模式:工厂模式定义了一个创建对象的接口,由子类进行对象的初始化,即工厂模式将子类的初始化推迟到了子类里。
抽象工厂模式:抽象工厂模式和工厂模式很相似,只是它利用接口或者抽象类定义了一个产品族,例如定义一个拨号产品族,只定义功能,不 关心实现,具体实现交由Android、iOS等操作系统自己完成。
1.4 简单工厂模式
模式定义

根据传入的参数决定实例化哪个对象。

简单工厂模式是工厂模式的简化版本,无需定义抽象工厂,通常还可以利用反射来生成对象,简化操作,如下所示:

// 简单工厂
public class SimpleFactory {

    public static <T extends AbstractProduct> T create(Class<T> clasz) {
        AbstractProduct product = null;
        try {
            product = (AbstractProduct) Class.forName(clasz.getName()).newInstance();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
        return (T) product;
    }
}
优点:
缺点:
1.5 工厂模式
模式定义

工厂模式定义了一个创建对象的接口,由子类进行对象的初始化,即工厂模式将子类的初始化推迟到了子类里。抽象工厂模式

优点:工厂模式符合开闭原则,当需要增加一个新产品时,只需要增加一个具体产品类和一个具体工厂类,无需修改原有的系统,外界也无需 知道具体的产品类的实现。
缺点:每次增加新产品的时候都会增加产品类和工厂类,势必会让系统越来越庞大。
工厂模式的实现也很简单,就是定义一个抽象类或者接口工厂,在子类工厂中决定实例化具体的类。

// 抽象工厂
public abstract class AbstractFactory {
    public abstract AbstractProduct create();
}

// 具体工厂
public class ConcretetFactory {

    public static AbstractProduct create() {
        return new ConcreteProductA();
//        return new ConcreteProductB();
    }
}

// 抽象产品
public class AbstractProduct {
}

// 具体产品A
public class ConcreteProductA extends AbstractProduct {
}

// 具体产品B
public class ConcreteProductB extends AbstractProduct {
}
1.6 抽象工厂模式
模式定义

抽象工厂模式和工厂模式很相似,只是它利用接口或者抽象类定义了一个产品族,例如定义一个拨号产品族,只定义功能,不 关心实现,具体实现交由Android、iOS等操作系统自己完成。

优点:
缺点:
实现如下所示:

// 抽象产品A
public abstract class AbstractProductA {
}

// 抽象产品B
public abstract class AbstractProductB {
}

// 具体产品A1
public class ConcreteProductA1 extends AbstractProductA{
}

// 具体产品A2
public class ConcreteProductA2 extends AbstractProductA {
}

// 具体产品B1
public class ConcreteProductB1 extends AbstractProductB {
}

// 具体产品B2
public class ConcreteProductB2 extends AbstractProductB {
}

// 抽象工厂
public abstract class AbstractFactory {
    
    public abstract AbstractProductA createProductA();
    public abstract AbstractProductB createProductB();
}

// 具体工厂
public class ConcreteFactory extends AbstractFactory {
    
    @Override
    public AbstractProductA createProductA() {
        return new ConcreteProductA1();
    }

    @Override
    public AbstractProductB createProductB() {
        return new ConcreteProductB1();
    }
}
二 组合型设计模式
2.1 适配器模式
模式定义

适配器模式可以将一个类的接口,转换成客户端期望的另一个接口,让两个原本不兼容的接口可以无缝对接。

优点:
缺点:
// 目标接口
public interface TargetInterface {
    int getFive();
}

// 被适配对象
public class Adaptee {

    public int getTen() {
        return 10;
    }
}

// 适配器
public class Adapter extends Adaptee implements TargetInterface {

    @Override
    public int getFive() {
        return 5;
    }
}
2.2 组合模式
模式定义

将对象组成树形结构以表示整体-部分的层次结构,使得用户对单个对象和组合对象的使用具有一致性。

应用场景

表示对象部分-整体的层次结构。
从一个整体中能够独立出部分模块或者功能的场景。
2.3 装饰模式
模式定义

动态的为对象增加一些额外的功能。

应用场景

需要透明且动态的扩展类的功能时。
// 抽象组件类
public abstract class AbstractComponent {
    
    protected abstract void operation();
}

// 具体组件类
public class ConcreteComponent extends AbstractComponent {
    @Override
    protected void operation() {
        
    }
}

// 抽象装饰类
public abstract class AbstractDecorator extends AbstractComponent {

    private AbstractComponent mComponent;

    public AbstractDecorator(AbstractComponent component) {
        mComponent = component;
    }

    @Override
    protected void operation() {
        mComponent.operation();
    }
}

// 具体装饰类
public class ConcreteDecorator extends AbstractDecorator {

    public ConcreteDecorator(AbstractComponent component) {
        super(component);
    }

    @Override
    protected void operation() {
        operationA();
        super.operation();
        operationB();
    }

    private void operationA() {

    }

    private void operationB() {

    }
}
2.4 外观模式
模式定义

要求一个字系统的外部与其内部的通信都通过一个统一的而对象进行。

应用场景

子系统在迭代的过程中可以会不断变化,甚至被替代掉,给一个统一的访问接口,避免子系统的改变影响到外部的调用者。
当需要构建层次结构型的系统时,为各层子系统提供访问的接口进行通信,避免直接产生依赖。
// 列表接口
public interface List {
    
    void add();
    void remove();
    
}

// 数组列表
public class ArrayList implements List {
    @Override
    public void add() {

    }

    @Override
    public void remove() {

    }
}

// 链表列表
public class LinkedList implements List {
    @Override
    public void add() {

    }

    @Override
    public void remove() {

    }
}
2.5 桥接模式
模式定义

将抽象部分和实现部分相互分离,使它们可以独立变化。

应用场景

如果一个系统需要在抽象部分和实现部分增加更多的灵活性,避免两种变化的时候相互影响。
如果不希望使用继承而增加系统的复杂度,可以考虑使用桥接模式。
一个类存在两个独立变化的纬度,且这两个纬度都希望进行扩展。
2.6 享元模式
模式定义

使用共享对象可以有效的支持大量的细粒度对象。

应用场景

系统中存在着大量的相似对象。
细粒度的对象都具有较接近的外部状态,而且内部状态与外部环境无关。
需要缓冲池的场景。
2.7 代理模式
模式定义

为其他对象提供一个代理以提供对这个对象的访问。

应用场景

当无法或者不想直接访问某个对象时,可以通过一个代理对象进行访问。
代理模式按照代理类运行前是否存在还可以分为静态代理和动态代理,如下所示:

静态代理

// 被代理接口,定义要实现的功能。
public interface Subject {

    void visit();
}

// 被代理类,完成实际的功能。
public class ConcreteSubject implements Subject {

    @Override
    public void visit() {
        System.out.println("visit");
    }
}

// 静态代理类,与被代理类实现同一套接口
public class StaticProxy implements Subject {

    private Subject mSubject;

    public StaticProxy(Subject subject) {
        mSubject = subject;
    }

    @Override
    public void visit() {
        mSubject.visit();
    }
}
动态代理

// 被代理接口,定义要实现的功能。
public interface Subject {

    void visit();
}

// 被代理类,完成实际的功能。
public class ConcreteSubject implements Subject {

    @Override
    public void visit() {
        System.out.println("visit");
    }
}

// 动态代理类,实现InvocationHandler接口。
public class DynamicProxy implements InvocationHandler {

    private Subject mSubject;

    public DynamicProxy(Subject subject) {
        mSubject = subject;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

        System.out.println("函数执行前自定义操作");
        // 调用被代理类的方法时会调用该方法
        method.invoke(mSubject, args);
        System.out.println("函数执行后自定义操作");
        return null;
    }
}

public class Client {

    public static void main(String[] args) {

        Subject subject = new ConcreteSubject();
        DynamicProxy proxy = new DynamicProxy(subject);

        // 动态生成代理类
        Subject proxySubject = (Subject) Proxy.newProxyInstance(DynamicProxy.class.getClassLoader()
                , subject.getClass().getInterfaces()
                , proxy);
        proxySubject.visit();

    }
}
三 行为型设计模式
3.1 模板模式
模式定义

定义一个操作的算法框架,而将具体实现延迟到子类中进行,使得子类在不改变整体算法框架的基础上,可以自定义算法实现。

应用场景

多个子类有公有的方法,并且逻辑基本相同时。
重要复杂的算法可以把核心算法设计为模板方法,具体细节则由子类实现
重构代码时,把相同的代码抽取到父类中,然后通过钩子函数约束其行为。
3.2 解释器模式
模式定义

给定一个语音,定义它的文法的一种表示,并定义一个解释器。

应用场景

如果某个简单的语音需要解释执行并且可以将该语言中的语句表示为一个抽象语法树时可以使用解释器模式。
在某些特定领域不断出现的问题是,可以将该领域的问题转船为一种语法规则下的语句,然后构建解释器来解释该语句。
3.3 策略模式
模式定义

策略模式定义了一系列算法,并将算法封装起来可以互相替换,策略模式让算法与使用它的客户端解耦,可以独立变化。

应用场景

针对同一类型的问题有多种处理方式,仅仅是具体的行为有差别时。
需要安全的封装多种同一类型的操作时。
出现同一抽象类的多个字类,而又需要使用if-else来选择子类时。
策略模式的实现也非常简单,依赖于接口或者抽象类,如下所示:

// 策略接口,定义功能。
public interface IStrategy {
    void method();
}

// 策略A
public class StrategyA implements IStrategy {
    @Override
    public void method() {

    }
}

// 策略B
public class StrategyB implements IStrategy {
    @Override
    public void method() {
        
    }
}
3.4 状态模式
模式定义

允许一个对象在内部状态改变时改变它的行为。

应用场景

一个对象的行为取决于它的状态,并且它在运行时根据状态改变它的行为。
代码中包含大量与对象状态相关的判断语句。
状态模式的核心是根据不同的状态对应不同的操作,如下所示:

// 操作接口
public interface TVState {
    void nextChannel();

    void lastChannel();
}

// 开机状态
public class PowerOnState implements TVState {

    @Override
    public void nextChannel() {
        // next channel 
    }

    @Override
    public void lastChannel() {
        // last channel
    }
}

// 关机状态
public class PowerOffChannel implements TVState {
    @Override
    public void nextChannel() {
        // do nothing
    }

    @Override
    public void lastChannel() {
        // do nothing
    }
}
3.5 观察者模式
模式定义

定义对象间一对多的依赖关系,每当这个对象发生改变时,其他对象都能收到通知并更新自己。

应用场景

关联行为场景
事件多级触发场景
跨系统的消息交换场景,例如消息队列,事件总线的处理机制。
观察者模式的实现如下所示:

// 监听接口,通知被监听对象发生改变
public interface Listener {

    void change();
}

// 被监听者
public class Observable {

    private Listener mListener;

    // 设置监听器
    public void setListener(Listener listener) {
        mListener = listener;
    }

    public void onChange() {
        // 通知对象发生改变
        mListener.change();
    }
}

// 监听者
public class Observer {

    public void setup() {
        Observable observable = new Observable();
        observable.setListener(new Listener() {
            @Override
            public void change() {
                // TODO 监听的对象发生改变
            }
        });
    }
}
3.6 备忘录模式
模式定义

在不破坏封装的前提下,保存一个对象的内部状态,并在该对象之外保存这个状态,以便可以将该对象恢复到保存时的状态。

应用场景

需要保存某个对象在某一时刻的状态。
外界向访问对象的状态,但是又不想直接暴露接口给外部,这时候可以将对象状态保存下来,间接的暴露给外部。
3.7 中介者模式
模式定义

中介者模式定义了一系列对象间的交互方式,使得这些对象像话作用而又不耦合在一起。

应用场景

当对象间有很多的交互操作,而且一个对象的行为依赖于其他对象时,可以利用中介者模式解决紧耦合的问题。
3.8 命令模式
模式定义

将一个请求封装成一个对象,可以将不同的请求参数化,可以对请求就行排队、日志记录以及撤销等操作。

应用场景

需要抽象待执行的动作,然后以参数的形式提供出来。
在不同的时刻,指定和排列请求。
需要支持撤销操作。
需要支持日志功能,这样当系统崩溃时,可以重做一遍。
需要支持事务操作。
命令模式的实现如下所示:

// 接收命令
public class Receiver {

    public void action() {
        // TODO 真正执行命令具体逻辑
    }
}

// 抽象命令
public interface AbstractCommand {
    
    // 执行命令
    void command();
}

// 具体命令
public class ConcreteCommand implements AbstractCommand {

    private Receiver mReceiver;

    public ConcreteCommand(Receiver receiver) {
        mReceiver = receiver;
    }

    @Override
    public void command() {
        mReceiver.action();
    }
}

// 调用者
public class Invoker {

    private AbstractCommand mCommmand;

    public Invoker(AbstractCommand command) {
        mCommmand = command;
    }

    public void invoke() {
        mCommmand.command();
    }
}
3.9 访问者模式
模式定义

封装一些作用于某些数据结构中的各元素的操作,它可以在不改变数据结构的前提下赋予这些元素新的操作。

应用场景

对象结构比较稳定,但是需要在对象结构的基础上定义新的操作。
需要对同一个类的不同对象执行不不同的操作,但是不希望增加操作的时候改变这些类。
3.10 责任链模式
模式定义

将请求的发送者和接收者进行解耦,使得多个对象都有机会处理该请求,将这些对象串成一条链,并沿着这条链子处理请求,直到有对象处理它为止。

应用场景

多个对象可以处理同一个请求,但是具体由哪个对象处理在运行时动态决定。
在请求处理者不明确的情况下向多个对象中的一个提交请求。
需要动态指定一组对象的处理请求。
责任链模式的实现主要在于处理器的迭代,要么使用循环迭代,要么使用链表后继,如下所示:

// 处理器,定位行为和下一个处理器
public abstract class Handler {
    protected Handler next;

    public abstract void handleRequest(String condition);
}

// 处理器1
public class Handler1 extends Handler {
    @Override
    public void handleRequest(String condition) {
        if (TextUtils.equals(condition, "Handler1")) {
            // process request
        } else {
            // next handler
            next.handleRequest(condition);
        }
    }
}

// 处理器2
public class Handler2 extends Handler {
    
    @Override
    public void handleRequest(String condition) {
        if (TextUtils.equals(condition, "Handler2")) {
            // process request
        } else {
            // next handler
            next.handleRequest(condition);
        }
    }
}
3.11 迭代器模式
模式定义

提供一个方法顺序访问一个容器内的元素,而又不暴露该对象的内部表示。

应用场景

遍历一个容器时。
--------------------- 

原文:https://blog.csdn.net/wy391920778/article/details/79621941 
 

猜你喜欢

转载自blog.csdn.net/lizhenxiqnmlgb/article/details/84679666
今日推荐