一个设计模式和七个小矮人原则-通俗易懂解

自己开发了一个股票智能分析软件,功能很强大,需要的点击下面的链接获取:

https://www.cnblogs.com/bclshuai/p/11380657.html

设计模式

 

目录

1      设计模式简介... 2

1.1     定义... 2

1.2     设计模式的七大原则... 2

2      设计模式的分类... 3

3      创建型模式... 3

3.1     工厂模式... 4

3.1.1     简单工厂模式—switch分类型创建水果对象... 4

3.1.2     工厂方法模式—封装水果工厂类... 6

3.1.3     抽象工厂模式-抽象水果工厂类... 7

3.2     单例模式... 9

3.3     建造者模型-构造多变... 10

3.4     原型模型-复制clone. 10

4      结构型模式... 10

4.1     适配器模式—改变接口对内统一... 10

4.2     桥接模式-多属性连接... 11

4.3     组合模式-父子结构相似... 12

4.3.1     透明方式... 12

4.3.2     安全方式... 13

4.4     装饰模式-添加额外属性... 14

4.5     外观模式-简化内部... 18

4.6     享元模式-池共享... 19

4.7     代理模式-控制... 20

5      行为性模型... 20

5.1     迭代器模式—遍历... 20

5.2     备忘录模式—保存还原... 23

5.3     策略模式—多态不同策略方法... 24

5.4     访问者模式—同一数据结构不同输出内容... 24

5.5     中介者模式-简化耦合关系多对多转为1对多... 26

5.6     解释器模式—解释执行... 26

5.7     职责链模式—流程链式... 26

5.8     状态模式—分支控制替代switch. 27

5.9     命令模式—命令封装保存恢复... 27

5.10       模板模式—定义步骤具体实现... 31

5.11       观察者模式-订阅发布... 32

1       设计模式简介

1.1  定义

设计模式是指在面向对象的程序开发中总结的一些规律方法,可以使得编程结构清晰,耦合度低,是一些常用的编程结构方法和模式。

高内聚:就是指相近的功能应该放到同一个类中,不相近的功能不要放到同一个类中。相近的功能往往会被同时修改,放到同一个类中,修改会比较集中,代码容易维护。

松耦合:就是类与类之间的依赖关系简单清晰。即使两个类有依赖关系,一个类的代码改动不会或很少导致依赖类的代码改动。比如依赖注入、接口隔离、基于接口而非实现编程。

1.2  设计模式的七大原则

(1)   单一原则(Single Responsibility Principle):一个类或者一个方法只负责一项职责,尽量做到类的只有一个行为原因引起变化。例如苹果工厂类构造苹果,梨子工厂类构造梨子。

(2)   开闭原则,允许对类进行继承扩展,不允许对源代码进行修改。例如水果工厂类中每增加一个水果,都要对水果工厂类进行修改,重新编译。如果水果工厂类fruitfactory只是定义接口,苹果applefactory、梨子pearfactory等工厂类单独继承fruitfactory接口类,创建不同的水果对象。各种水果的创建互不影响。新增水果,只要新增一种水果类继承fruitfactory,不会对fruitfactory类进行修改,这就是对扩展开发,对修改关闭。

(3)   里氏替换原则(LSP liskov substitution principle):子类不允许修改父类接口的功能。例如父类接口add是加的作用,子类不能讲add变成减法。

(4)   依赖倒转原则,面向接口编程,巧用多态。

(5)   接口隔离原则,将接口细化类继承接口,类中不需要实现不需要的接口。

(6)   迪米特法则,最小关系原则。不该有直接依赖关系的类之间,不要有依赖;有依赖关系的类之间,尽量只依赖必要的接口。

(7)   合成聚合复用原则,尽量不使用继承,而是通过过定义接口,子类A实现接口,在需要使用子类对象的类B中定义接口引用,传入子类对象A,子类对象成为B的一部分,可以在B中调用A的接口。通过这种方式,避免使用继承,因为继承中父类会暴露实现细节给子类,父类的实现发生改变,那么子类的实现也不得不发生改变

2       设计模式的分类

 

3       创建型模式

3.1  工厂模式

平时创建对象都是调用类的构造函数去new一个对象,创建不同的对象要知道不同对象的实现类。增加了类之间的联系和耦合。工厂模式则是将对象的构造封装在工厂内部,只需要调用工厂的方法,传入类名称,工厂就会返回的创建的对象。如果需要对创建对象进行修改,只需要修改工厂类即可,不需要修改调用者的代码。实现松耦合。工厂模式分为简单工厂模式、工厂方法模式、抽象工厂模式。

简单工厂模式:用一个水果工厂类,通过switch判断不同的水果类型,创建水果对象。

工厂方法模式:一种水果采用一种工厂进行封装,修改水果,只要修改一个水果类,新增也只要新增一个水果类。apple用appleFactory,pear用pearFactory创建pear对象。

抽象工厂模式:采用抽象的工厂IFactory接口,所有的工厂Factory类都继承这个接口,创建水果工厂时,直接IFactory  iFactory=new appleFactory();创建工厂,在调用统一的方法创建水果。创建不同的水果时,只要在new工厂时换成其他工厂即可。

3.1.1         简单工厂模式—switch分类型创建水果对象

简单工厂模式就是将类的构造封装在工厂类中,例如水果工厂,新增一种水果,就增加一个分支构造。

 

如果水果的构造相当复杂,需要种子、阳光、水分等类,也可以在构造分支中一一创建种子、阳光、水分对象,在用这些对象去构造水果类对象返回。

 

优点:

(1)   封装可以降低重复代码量;

(2)   封装可以降低创建者和调用者之间的耦合程度,如果类的创建需要增加新的条件,可以直接在工厂中修改。

缺点:

(1)   一是如果需要生产的产品过多,此模式会导致工厂类过于庞大,承担过多的职责,变成超级类。违背了单一原则。

(2)   二是当要生产新的产品时,必须在工厂类中添加新的分支。违背了开闭原则。

3.1.2         工厂方法模式—封装水果工厂类

为了解决简单工厂模式的这两个弊端,工厂方法模式应运而生。一种水果用一个工厂类,apple用applefactory,pear用pearfactory。apple生产修改只要修改applefactory,符合单一原则,添加新的产品只要增加新的factory类,符合开闭原则。

 

优点:

(1)   apple生产修改只要修改applefactory,符合单一原则。

(2)   添加新的产品只要增加新的factory类,符合开闭原则。

缺点:

(1)   需要和applefactory、pearfactory类打交道,要使用几种水果,就要知道几种工厂类,耦合度没有降低,反而增加了代码量。

这样和直接 new 出苹果和梨子有什么区别?优势是在需要多个对象构造水果时,可以进行封装。

 

3.1.3         抽象工厂模式-抽象水果工厂类

抽象工厂模式就是使用虚函数,或者接口的形式将方法抽象出来,子类需要实现虚函数或者接口,用父类对象指针指向子类对象,只需要创建时指定子类对象,使用时调用通用的虚函数和接口即可。

定义接口:

 

创建对象时,只需要修改一行代码指定功能,适用对象都可以用通用接口。

 

优点:

(1)   符合单一原则和开闭原则;

(2)   通过抽象接口或者虚函数,降低耦合度,只要创建对象时指定具体工厂,使用时调用通用接口即可。

缺点:

(1)   ifactory如果要新增或者删除接口,则所有的factory类都要修改。

所以抽象工厂模式适用于增加同类工厂这样的横向扩展需求,不适合新增功能这样的纵向扩展。

3.2  单例模式

就相当于一个全局对象,采用静态变量的方式创建对象,全局调用。有一开始就创建好对象的饿汉模式和第一次调用时,才创建对象的懒汉模式。

饿汉模式

懒汉模式:调用时在创建对象。

 

在多线程调用时,会出现创建多个对象的问题,所以需要加上锁的安全懒汉模式

安全懒汉模式

 

3.3  建造者模型-构造多变

建造型模式用于创建过程稳定,但配置多变的对象。将一个复杂的构建与其表示相分离,使得同样的构建过程可以创建不同的表示。例如奶茶的创造过程,通过传入不同的参数,创造出不同的奶茶。

3.4  原型模型-复制clone

也就是复制模型,用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象。避免创建新的对象,然后再将属性一一设置,而是通过clone方法,创建对象,复制属性值。

4       结构型模式

4.1  适配器模式—改变接口对内统一

如电源适配器,将交流电转换为直流电,将220V转换为5V。使得接口兼容。再比如协议对接,将不同厂家的报警协议转换为海康报警协议,作为输入,传入系统。

4.2  桥接模式-多属性连接

物体有不同的属性,例如颜色和形状,颜色和形状之间没有继承关系,将形状和颜色分离,根据需要进行组合,将抽象部分和实现部分进行分离,使他们可以独立的变化,这就是桥接模式的思想。

例如饼干有红黑黄三种颜色,有三角、矩形、圆形三种形状,首先定义两个接口

public interface IShape {

    void draw();

}

public interface IColor {

String getColor();

}

不同颜色继承IColor接口

public class Red implements IColor {

@Override

public String getColor() {

   return "红";

    }

}

如果不同形状和颜色都要实现一个类,那一共是3*3=9个类,如果增加一颜色或者形状,就是3*4=12个类。类的数量会随着增加而增加。

class RedTriangle implements IShape , IColor {}

如果在每个形状中桥接IColor接口,通过set方法设置进去,就可以避免实现多个类。增加一种颜色,也不会要创建多个类。

class Triangle implements IShape {

  private IColor color;

void setColor(IColor color) {

this.color = color;

}

@Override

public void draw() {

System.out.println("绘制" + color.getColor() + "三角形");

}

}

结合实例说明概念,就是当类有多个同等级的属性时,可以将属性抽象为一个接口,它们可以独立的去继承变化,不同的颜色继承Icolor接口,不同的形状继承IShape接口,然后在形状类中通过setColor方法,将创建好的颜色对象设置进去,实现两个属性的桥接。这就是桥接模式,如果还有第三个属性口味,同样定义Itaste接口,实现不同的口味。

4.3  组合模式-父子结构相似

组合模式应用场景是树形组织结构的对象,例如文件夹内部有子文件夹和文件,子文件夹内部同样有这样的结构,或者领导下面管理了职员和组长,组长下面管理了职员和小组长,这种树形结构,而且子对象和父对象有相同的结构的应用场景适合组合模式。

文件和文件夹有不同的操作方法,文件有复制copy,delete方法,文件夹除了copy、delete方法,还有getchild方法,如果区别对待,需要定义不同的类,不能把文件和文件夹当作相同的对象来对待。为了使得文件和文件夹在使用时具有一致性,即用户不关心它是文件或文件夹,文件和文件夹的接口都是一样的。

组合模式又分为两种方式:透明方式和安全方式。

4.3.1         透明方式

透明方式是指让文件和文件夹具备完全一致的行为接口,调用者可以一致对待它们。文件的getchild接口返回为空。这样就可以把文件和文件夹看作相同的对象的来对待。缺点是文件不支持管理子文件夹和文件的功能,违背了接口隔离原则。文件在调用getchild接口时会导致程序出错,所以这种方式是不安全的。

即定义一个基类

public abstract class compotent

{

       compotent copy();

       void delete(String name);

List< compotent > getchild();

}

4.3.2         安全方式

是在基类component类中定义公共接口,然后继承类中定义特殊接口,如下所示。安全方式遵循了接口隔离原则,但需要区别对待文件和文件夹,不够透明。在使用组合模式时,需要根据实际情况决定。但大多数使用组合模式的场景都是采用的透明方式。

public abstract class compotent

{

       compotent copy();

       void delete(String name);

}

public file extends component

{

@Override

compotent copy()

{

****

}

@Override

       void delete(String name)

{

}

}

public dir extends component

{

@Override

compotent copy()

{

****

}

@Override

       void delete(String name)

{

}

List< compotent > getchild()

{

}

}

4.4  装饰模式-添加额外属性

装饰模式由装饰类对象和被装饰类对象,被装饰类对象作为形参传入装饰类内部,装饰类内部执行被装饰类的基本操作,同时加上额外的装饰操作。

装饰就是动态的给被装饰类增加一些功能或增加新特性,不是通过修改类,或者继承类来实现功能的增加,而是通过修饰来增加功能。类和修饰可以独立增长,不会耦合。例如奶茶和添加辅料之间可以独立扩展,有不同的奶茶:冰红茶、果汁茶,然后添加辅料有:加冰、加果粒、加红豆等。奶茶和辅料之间没有耦合,不是通过继承奶茶类来实现不同添加的奶茶。

 

Component是抽象构件,定义一个对象接口,可以给这些对象动态地添加职责;装饰模式中的类都要继承于它,实现接口operation执行功能。

ConreteComponent,被修饰的类,定义一个具体对象,也可以给这个对象添加一些职责;例如operation函数中输出奶茶。

Decorator是装饰抽象类,同样重写operation函数;不同的装饰类都是继承这个基类来实现。Decorator类中会有个Component的指针,通过ConreteDecorator类的构造函数传入具体的ConreteComponent给Component的指针。并且在operation函数中调用形参传入的ConreteComponent对象的operation函数。

ConreteDecorator是具体装饰对象,起到给Component添加职责的功能。例如给奶茶加冰、加红豆、加果粒等。修饰类构造函数参数中传入ConreteComponent被修饰类的对象,传给Decorator基类中的,ConreteComponent类中operation方法中调用super.operation();来调用Decorator的基类operation方法,Decorator基类中的operation方法中调用传入的ConreteComponent对象(也就是Component指针指向的对象)operation方法来实现基本操作,例如输出奶茶,同时ConreteComponent类中operation方法中会调用修饰方法来实现修饰操作,例如输出加冰、加果粒等。

(1)   定义Component定义接口

public abstract class Component {

     public abstract void operation();

 }

(2)定义ConcreteComponent类输出基本操作

public class ConcreteComponent extends Component {

    @Override

    public void operation() {

        System.out.println("奶茶");

    }

}

(3)定义抽象修饰类,包含Component指针,具体修饰类继承Decorator,通过构造函数传入被修饰类,operation函数则是调用被修饰函数的operation函数,输出基本操作。

public abstract class Decorator extends Component {

    private Component component = null;

    //通过构造函数传递给被修饰者

    public Decorator(Component component) {

        this.component = component;

    }

    //委托给被修饰者执行

    @Override

    public void operation() {

        if(component != null) {

            this.component.operation();

        }

    }

}

(4)实现具体修饰类,

public class zhenZhu extends Decorator {

    //定义被修饰者,传入被修饰对象

    public ZhenZhu (Component component) {

        super(component);//传给基类Decorator的component指针

    }

    //定义自己的修饰方法

    private void addzhenzhu() {

        System.out.println("加珍珠");

    }

    @Override

    public void operation() {

        super.operation();//输出基本操作:奶茶

this. addzhenzhu ();//输出修饰:珍珠

    }

}

//创建加红豆修饰类

public class hongdou extends Decorator {

    //定义被修饰者,传入被修饰对象

    public hongdou (Component component) {

        super(component);//传给基类Decorator的component指针

    }

    //定义自己的修饰方法

    private void addhongdou() {

        System.out.println("加红豆");

    }

    @Override

    public void operation() {

        super.operation();//输出基本操作:奶茶

this. addhongdou();//输出修饰:珍珠

    }

}

(8)   创建修饰类和被修饰类对象,执行修饰操作和基本操作;

public class Client {

    public static void main(String[] args) {

        Component component = new ConcreteComponent();//创建具体操作类对象

        //创建加珍珠修饰,并传入被修饰对象

       Component zhenzhu= new zhenZhu (component);//一次修饰

              Component hongdou= new hongDou (zhenzhu);//二次修饰

        //执行操作

        hongdou.operation();//输出:奶茶加珍珠加红豆

    }

}

平常当系统需要新功能时,是向旧的类中添加新的代码,这些新加的代码通常装饰了原有类的核心职责或主要行为,这种做法的问题在于,它们再主类中加入了新的字段、新的方法和新的逻辑,从而增加了主类的复杂度,而这些新加入的东西仅仅是为了满足一些只在某种特定情况下才会执行的特殊行为的需要。

而装饰模式却提供了一个非常好的解决方案,它把每个要装饰的功能放在单独的类中,并让这个类包装它所要装饰的对象。

https://www.cnblogs.com/adamjwh/p/9036358.html

https://www.zhihu.com/question/308850392

4.5  外观模式-简化内部

是一种封装的思维,子系统内部有很多的接口和操作,为子系统提供高层接口,提供给外面使用,封装内部复杂的逻辑。java中MVC中的Controller就是外观模式。或者API接口等。

优点

减少了系统的相互依赖

提高了灵活性。不管系统内部如何变化,只要不影响到外观对象,任你自由活动

提高了安全性。想让你访问子系统的哪些业务就开通哪些逻辑,不在外观上开通的方法,你就访问不到。

缺点

不符合开闭原则,修改很麻烦。

4.6  享元模式-池共享

享元模式是一种池的概念,例如String常量池,不同的字符串常量在常量池中都有唯一的字符串常量,不会有多个字符串副本。避免占用大量的重复空间。在有大量对象时,有可能会造成内存溢出,我们把其中共同的部分抽象出来,如果有相同的业务请求,直接返回在内存中已有的对象,避免重新创建。例如用 HashMap 存储key和对象,创建对象时先根据key去hashMap中寻找有没有创建,有则返回,无则创建。

应用场景:系统中有大量相似的对象,可以将相同的部分作为内部状态,共享使用, 不同的部分作为外部状态,去修改实现不同的外部特征。

内部状态:指对象共享出来的信息,存储在享元对象内部并且不会随环境的改变而改变;例如棋子的颜色是黑色和白色。

外部状态:指对象得以依赖的一个标记,是随环境改变而改变的、不可共享的状态。例如棋子的在棋盘中的位置。

优点

大大减少了对象的创建,降低了程序内存的占用,提高效率

缺点

提高了系统的复杂度。需要分离出内部状态和外部状态,而外部状态具有固化特性,不应该随着内部状态的改变而改变。

 

4.7  代理模式-控制

用另外的类去封装内部类的接口,并且增加一些权限控制之类。和与适配器模式的区别:适配器模式主要改变所考虑对象的接口,而代理模式不能改变所代理类的接口;与装饰模式区别:装饰模式是为了增强功能,而代理模式是为了加以控制;例如spring的AOP,电影明星的经纪人等。

5       行为性模型

5.1  迭代器模式—遍历

访问遍历一个聚合对象的内容无需暴露它的内部表示,Iterator迭代器对集合进行遍历,但迭代器模式算是一个没落的模式,基本上没人会单独写一个迭代器,除非是产品性质的开发。迭代器模式(Iterator),提供一种方法顺序访问一个聚合对象中各个元素,而又不暴露该对象的内部表示。

 

如图所示,迭代器抽象类iterator用于定义迭代器的接口,ConcreteIterator类则继承iterator类,实现接口。aggregate接口则定义了容器类的接口,如添加,删除,还有迭代器对象;ConcreteAggregate则实现容器类的接口,里面包含了用于存储数据的容器,同时将容器对象传递给ConcreteIterator类,ConcreteIterator类保存了容器vertor的引用,可以对容器进行迭代访问。

(1)Aggregate是聚集抽象类,负责提供创建具体迭代器角色的接口;

public interface Aggregate {

    public void add(Object object);

    public void remove(Object object);

    public Iterator iterator();

}

(2)ConcreteAggregate是具体聚集类,继承Aggregate,;

public class ConcreteAggregate implements Aggregate {

    private Vector vector = new Vector();

    @Override

    public void add(Object object) {

        this.vector.add(object);

    }

    public void remove(Object object) {

        this.remove(object);

    }

    @Override

    public Iterator iterator() {

        return new ConcreteIterator(this.vector);

    }

}

(3)Iterator是迭代抽象类,用于定义得到开始对象、得到下一个对象、判断是否到结尾、当前对象等抽象方法,统一接口;

public interface Iterator {

    public Object next();    //遍历到下一个元素

    public boolean hasNext();    //是否已经遍历到尾部

    public boolean remove();    //删除当前指向的元素

}

(4)ConcreteIterator是具体迭代器类,继承Iterator,实现开始、下一个、是否结尾、当前对象等方法。

public class ConcreteIterator implements Iterator {

    private Vector vector = new Vector();

    public int cursor = 0;    //定义当前游标

    public ConcreteIterator(Vector vector) {

        this.vector = vector;

    }

    @Override

    public Object next() {

        Object result = null;

        if (this.hasNext()) {

            result = this.vector.get(this.cursor ++);

        } else {

            result = null;

        }

        return result;

    }

    @Override

    public boolean hasNext() {

        if (this.cursor == this.vector.size()) {

            return false;

        }

        return true;

    }

    @Override

    public boolean remove() {

        this.vector.remove(this.cursor);

        return true;

    }

}

5.2  备忘录模式—保存还原

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

 

Oreginator创建一个备忘录,保存状态,将备忘录对象交给Caretaker管理,恢复状态时,从Caretaker获取备忘录对象,还原状态。

Originator是发起人,负责创建一个备忘录Memento,用以记录当前时刻它的内部状态,并可使用备忘录恢复内部状态;

Memento是备忘录,负责存储Originator对象的内部状态,并可防止Originator以外的其他对象访问备忘录Memento;

Caretaker是管理者,负责保存好备忘录的Memento,不能对备忘录的内容进行操作或检查。

应用场景:

需要保存和恢复数据的相关场景,例如游戏的存档。

5.3  策略模式—多态不同策略方法

策略模式是定义了一组算法,将每个算法都封装起来,并且使它们之间可以互换。类似于多态,例如去旅游,有不同的策略:汽车、火车、飞机。或者数据库连接操作:mysql,oracle,pg等,可以将各种数据库统一接口,各自封装,根据项目现场的情况使用不同的数据库,切换不同的数据库对象。

 

Strategy是策略类,用于定义所有支持算法的公共接口;

ConcreteStrategy是具体策略类,封装了具体的算法或行为,继承于Strategy。

Context是上下文,维护一个对Strategy对象的引用;传入不同的策略ConcreteStrategy对象,实现不同的算法调用。

5.4  访问者模式—同一数据结构不同输出内容

访问者模式是对于一个数据结构进行访问,如果希望不同的访问者去访问会有不同的输出结果。例如员工的数据结构对象,经理想看员工kpi,HR想看员工的工作背景。如果要新增一个访问者,例如财务想看员工的工资,则重新定义一个财务访问对象,定义想要输出的方法和输出的内容。把访问者对象传递给数据结构对象,就可以输出不同的访问结果。访问者模式是一种将数据操作和数据结构分离的设计模式。将访问者对象以参数形式传递给被访问者,访问者对象访问不同的元素,输出不同的结果。

 

Element:元素接口或者抽象类,相当于例子中的员工,它定义了一个接受访问者(accept)的方法,其意义是指每一个元素都要可以被访问者访问。Element会有一个accept来接收不同的访问者访问,输出不同的结果。

ElementA、ElementB:是具体的元素类,相当于例子中的工程师、测试、项目经理等具体的员工。它提供接受访问的具体实现,而这个具体的实现,通常情况下是使用访问者提供的访问该元素类的方法。

Visitor:访问者的抽象类,定义接口,定义了对每个 Element (工程师、测试、项目经理)访问的行为,它的参数就是被访问的元素,它的方法个数理论上与元素的个数是一样的,因此,访问者模式要求元素的类型要稳定,如果经常添加、移除元素类,必然会导致频繁地修改 Visitor 接口,如果出现这种情况,则说明不适合使用访问者模式。

ConcreteVisitor:具体的访问者,例如财务访问者输出工资;总监访问产品经理,输出产品数量,访问工程师输出代码量,它需要给出对每一个元素类访问时所产生的具体行为。

ObjectStructure:定义当中所提到的对象结构,相当于一个公司或者一个部门,它内部管理了元素集合,并且可以迭代这些元素提供给不同的访问者访问。

访问者模式例子

https://www.jianshu.com/p/1f1049d0a0f4

5.5  中介者模式-简化耦合关系多对多转为1对多

中介模式的设计思想跟中间层很像,通过引入中介这个中间层,将一组对象之间的交互关系(或者说依赖关系)从多对多(网状关系)转换为一对多(星状关系)。原来一个对象要跟n个对象交互,现在只需要跟一个中介对象交互,从而最小化对象之间的交互关系,减小了耦合度,降低了代码的复杂度,提高了代码的可读性和可维护性。

外观模式—外观模式注重的是简化接口,简化组件系统与外部程序的依赖关系。提供一个更高层次的统一接口,使子系统更加简便的使用。

代理模式—注重的是对其他对象的访问控制、倾向于的是一对一的关系处理。

中介者模式—注重的是将多对多的关系处理封装到一对多、通过一个中介者对象对多个对象之间的依赖进行解耦。

5.6  解释器模式—解释执行

在需要解释执行的场景,例如编译器、运算表达式、机器人听从命令,需要先解释成机器语言,然后再去执行命令。

5.7  职责链模式—流程链式

像流程审批类的应用场景,需要一级一级的向上审批,形成一个链式的处理过程,比如去医院开具病假条,普通医生只能开一天的证明,如果需要更多时常,则需将开具职责转交到上级去,上级医师只能开三天证明,如需更多时常,则需将职责转交到他的上级,以此类推,这就是一个职责链模式的典型应用。

5.8   状态模式—分支控制替代switch

开发中需要根据不同的状态,来执行不同的操作,通常采用switch…case或if…else语句方式判断不同的状态,然后进行相应的处理,但是增加一种状态,就需要修改主类进行添加。不符合开闭原则和单一职责原则。所以采用状态模式

State定义状态抽象类State,定义状态处理方法Handle();定义具体状态处理类ConcreteState类继承State,实现不同状态下的处理方法。

Context类为环境角色,内部有一个State的引用,传入不同的ConcreteState子类的实例,用Handle方法执行不同的状态下的操作。当有新的状态时,只要继承State类实现新状态下的操作,然后传递给Context类,无需修改Context的代码。

 

5.9  命令模式—命令封装保存恢复

定义:将请求封装成一个对象,从而让用户使用不同的请求把客户端参数化,以及支持可撤销和恢复的功能。

人操作遥控器来控制电视机为例,命令模式中的有四个角色;人、遥控器、命令、电视机。

Command:电视机的控制请求,控制请求方法被封装成一个命令对象,就像遥控器上的一个个按钮一样,人通过操作命令对象来操作请求方法。

Receiver:有命令,当然有命令的接收者对象:电视机Receiver接收人的控制命令,接收执行命令。

Client:人通过按钮来创建命令,这里就引出了客户端Client对象。

Invoker:遥控器负责使用客户端创建的命令对象。该Invoker对象负责要求命令对象执行请求,通常会持有命令对象,可以持有很多的命令对象。

(1)不使用命令模式

不使用命令模式时,定义不同的方法,没新增一个频道 ,就要添加一个方法。

public class Television {

    public void playCctv1() {

        System.out.println("--CCTV1--");

    }

    public void playCctv2() {

        System.out.println("--CCTV2--");

    }

    public void playCctv3() {

        System.out.println("--CCTV3--");

    }

    public void playCctv4() {

        System.out.println("--CCTV4--");

    }

    public void playCctv5() {

        System.out.println("--CCTV5--");

    }

    public void playCctv6() {

        System.out.println("--CCTV6--");

    }

}

(2)   使用命令模式

就是将各个方法定义成一个对象,首先要定义一个抽象的命令类

public abstract class Command {

    //命令接收者:电视机

    protected Television television;

    public Command(Television television) {

        this.television = television;

    }

    //命令执行

    abstract void execute();

}

然后再将各个方法封装成对象

//播放cctv1的命令

public class CCTV1Command extends Command {

    @Override

    void execute() {

        television.playCctv1();

    }

}

//播放cctv2的命令

public class CCTV6Command extends Command {

    @Override

    void execute() {

        television.playCctv2();

    }

}

。。。。。。。。

//播放cctv6的命令

public class CCTV1Command extends Command {

    @Override

    void execute() {

        television.playCctv6();

    }

}

引入命令的调用着Invoker对象了,在此例子中电视遥控器TeleController就是扮演的这个角色,用来执行和保存命令。

public class TeleController {

    //播放记录

    List<Command> historyCommand = new ArrayList<Command>();

    //切换卫视

    public void switchCommand(Command command) {

        historyCommand.add(command);

        command.execute();

    }

    //遥控器返回命令

    public void back() {

        if (historyCommand.isEmpty()) {

            return;

        }

        int size = historyCommand.size();

        int preIndex = size-2<=0?0:size-2;

        //获取上一个播放某卫视的命令

        Command preCommand = historyCommand.remove(preIndex);

        preCommand.execute();

    }

}

Client的操作如下

       //创建一个电视机

        Television tv = new Television();

        //创建一个遥控器

        TeleController teleController = new TeleController();

        teleController.switchCommand(new CCTV1Command(tv));

        teleController.switchCommand(new CCTV2Command(tv));

        teleController.switchCommand(new CCTV4Command(tv));

        teleController.switchCommand(new CCTV3Command(tv));

        teleController.switchCommand(new CCTV5Command(tv));

        teleController.switchCommand(new CCTV1Command(tv));

        teleController.switchCommand(new CCTV6Command(tv));

        System.out.println("------返回上一个卫视--------");

        //模拟遥控器返回键

        teleController.back();

        teleController.back();

总结:命令模式的主要特点就是将请求封装成一个个Commond命令,以命令为参数来传递给invoke来执行命令和保存命令,达到请求参数化的目的,且保存命令,可以进行回退操作。而且如果需要添加新的电视频道,只需要添加新的命令类即可。而非命令模式中,看电视的人和电视耦合在一起;

https://blog.csdn.net/chunqiuwei/article/details/79030816

5.10         模板模式—定义步骤具体实现

 接口抽象和继承实现。通俗点的理解就是 :完成一件事情,有固定的数个步骤,但是每个步骤根据对象的不同,而实现细节不同;就可以在父类中定义一个完成该事情的总方法,按照完成事件需要的步骤去调用其每个步骤的实现方法。每个步骤的具体实现,由子类完成。

5.11         观察者模式-订阅发布

观察者模式(Observer),又叫发布-订阅模式(Publish/Subscribe),定义对象间一种一对多的依赖关系,使得每当一个对象改变状态,则所有依赖于它的对象都会得到通知并自动更新。

比如在学校上自习的时候,大家肯定都有过交头接耳、各种玩耍的经历,这时总会有一个“放风”的小伙伴,所有在玩的学生都关心老师来没来这个信息,但是不能所有的学生都去观察老师来没来,我们派一个观察者去观察老师来,在玩的学生会提前跟观察者大号招呼,老师来了要告诉他,这是消息的订阅,当老师即将出现时及时“通知”大家老师来了,把消息发送给所有打过招呼的学生,这是消息的发布。

 

Observer是观察者抽象类,定义接口;

ConcreObserver是具体的实现类;表示各种不同观察类型的对象。实现抽象观察者角色所要求的更新接口,以便使本身的状态与主题的状态相协同。

subject主题抽象类;

ConcreteSubject类是具体主题,保存着不同的ConcreObserver对象,进行登记,在具体主题内部状态改变时,给所有登记过的观察者发出通知;

自己开发了一个股票智能分析软件,功能很强大,需要的点击下面的链接获取: https://www.cnblogs.com/bclshuai/p/11380657.html
原文地址:https://www.cnblogs.com/bclshuai/p/14717967.html