设计模式

设计模式的要点就是“寻找变化点,然后在变化点出应用设计模式,从而来更好的应对需求的变化”

“组件协作”模式

“组件协作”模式通过晚绑定,来实现框架和程序之间的松耦合,是二者之间协作的时候常用的模式。

动机:就是确定稳定操作结构的前提下,来灵活的应对各个子步骤的变化或者晚期的需求。

1. 模板方法

比如在一个框架中,我们要进行某项操作的过程是确定的,但是里面的实现方法不是确定,此时,我们就会将过程定义为普通的函数,将不确定的方法定义为虚函数,如果用户调用该接口的时候,那么就需要重新定义它子集特有的方法。

如果我们不使用模板方法,那么,在框架中,我们只能确定的写出整个流程中确定的那几部,然后在实现的时候,我们需要自己写出特有的几个步骤,然后才能写完整个流程。

2. 策略模式

比如说,在计算所得税的时候,每个国家的税率有所不同,如果不采用模式,我们可能会将各个国家的税率枚举出来,然后在真正操作的时候,我们利用if...else...来判断当前到底应该应用那种税率。

使用设计模式之后,我们可以将计算所得税的方法抽象,然后每个国家的具体计算所得税的实现继承该抽象类。我们高层调用的时候是直接使用抽象类的指针,这里面和前面将的依赖倒置原则差不多。

3. 观察者模式

比如我们在编写一个下载文件的界面的时候,突然来一个需求,要求设置一个进度条,展示已下载文件的百分比。如果不使用设计模式,我们可能是在实现的时候,会先定义一个控件,然后利用这个控件来展示显示的百分比。但是如果我们现在需求变更了,不是利用一个进度条来展示下载的百分比,而是直接将下载的百分比打印出来,那么前面我们利用一个进度条展示的那个代码,就应该变化。现在使用了观察者设计模式,我们定义了一个抽象类,这个抽象类里面定义了一个抽象方法,这个抽象方法,就是表示收到通知之后,具体要干嘛。我们在实现的时候,只需要使用抽象类的指针,然后对调用里面的方法。至于具体实现的细节,我们自己继承这个抽象类,然后实现。

单一职责模式

在软件组件的设计中,如果责任划分的不是很清晰,使用继承得到的结果往往是随着需求的变化,子类急剧膨胀,同时充斥着重复代码,这个时候的关键是划分责任。

1. 装饰模式

比如说,我们现在定义了一个抽象的流类,里面有抽象方法,包括读流和写流等操作。现在有具体的文件流网络流来继承这个抽象类,并在读各种文件流的时候,涉及到解密操作,写各种流的时候,涉及到加密操作。如果不使用设计模式,我们可能会对每种具体文件流进行继承。然后分别实现他们在读写的解密和加密操作。比如我们继承文件流类,然后重写里面的读写操作,以实现加密和解密。

这样做的弊端是,对于每个具体的流对象,我们都要用继承的方法重写里面的读写方法。然后实现加密和解密,但是其实对于每个流对象,我们只是读写流的方式不同,但是加密和解密的操作是不同。我们对每个具体的流都具体定义的话,那么必然会增加很多的重复代码。

如果将加密和解密的操作定义到一个另一个类中,利用使用一个抽象类的对象指针,来表明具体是哪个类。有以前的静态绑定变换为动态绑定。这样就减少了代码量,这样的模式就是装饰模式。

2. 桥模式

比如我们定义了一个消息类,这个类包括有包括有每个消息类必备的功能,比如说登录,发送消息等功能,还有一些,播放声音,链接网络等功能,这写功能在每个平台上都设计方法都是不一样的。我们很容易的想到对于每个平台,我们都重写每个平台的特有的功能。然后在每个平台在具体实现的时候,再去继承它所属的平台。现在我们有两个平台,每个平台都有两个具体的实现的类。如果不适用设计模式,我们可能会定义两个平台抽象类,然后再每个平台写两个具体的抽象类。

如果两个平台的抽象类实现的功能类似,那么我们知道,可以将他们继承的平台定义为一个Message的指针,从而实现多台。但是我们知道平台只是实现了Message类的部分函数,那么它仍然是一个抽象类,我们是不能创建平台类的对象的。所以我们可以将Message中与平台无关的方法分离为一个类,其他与平台有关的再抽象为一个类,平台类在实现的实现只是继承哪个与平台有关的抽象类。

“对象”创建模式

1. 工厂模式

根据设计原则,我们知道高层不应该依赖于底层,应该依赖于抽象。比如现在我们定义一个框架类,这个框架类,利用用到了流类对象,假如这个流类对象有多个具体的实现,而我们在框架调用的时候,我们肯定是利用一个抽象指针去接收不同new的实例对象。但是高层是不应该一来底层的,也就是说,我们在高层框架中直接去调用具体类的构造函数,这个时候怎么办呢?我们就定义一个抽象类,这个抽象类有一个函数,这个函数的作用就是返回一个具体类的实例对象,然后每个具体的类都去实现它。这样我们在高层的时候,就可以直接使用这个抽象的工厂类,而不直接调用具体类的方法。

2. 抽象工厂

比如说,现在我们有这样一个需求,我们需要访问数据库,那么我们需要建立这个数据库的连接对象,需要建立数据库的命令的对象等等。我们知道数据库分为很多种,所有每一个具体数据库的连接,和建立命令对象可能会有所不同。我们利用工厂模式,先想到的是对每个数据库的连接创建一个工厂,每一个数据库命令创建一个工厂。但是如果分开创建工厂的话,我们在操作的时候,如果使用Oracle的数据连接对象,使用mysql的的命令对象,就会出现问题。所以这个时候最好是将相互关联的工厂在一个工厂类中实现。

提供一个接口,让该接口负责创建一系列“相关或者相互依赖的对象”,无需指定他们具体的类。

3. 原型模式

如果我们保留一个对象的中间状态,这个时候就可以用原型设计模式。

使用原型实例指定创建对象的种类,然后通过拷贝这些原型来创建新的对象。

4. 构建器模式

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

对象性能模式

1. 单例模式

将它的构造函数和拷贝够着函数,设置为私有

保证一个类仅有一个实例,并提供一个该实例的全局访问点。

2. 享元模式

相当于对象池。运用共享技术有效地支持大量细粒度的对象。它是使用共享技术来减少对象的个数。

“接口隔离”模式

1. 门面模式

门面模式简化了整个组件系统的接口,对于组件内部和外部客户程序来说,达到一种“解耦”的效果----内部子系统的任何变化不会影响到Facade的变化。比如说操作系统,将用户和硬件进行隔离,使得用户只需要使用稳定的接口,而不需要了解硬件的具体的变化。

2. 代理模式

在创建的时候,我们实际上应该是去new一个具体类的对象,但是由于某种特殊的原因,比如说需要进行访问安全控制,需要性能优化,需要分布式的原因等等。这些具体类的对象可能做不到,此时就利用代理模式来实现。

3. 适配器

就是实现将老的接口,或者现成的接口,转化为新的接口或者目标接口。实现方法一般是继承新街口,然后里面有一个老接口对象的指针,用这个老接口的函数来实现新接口。在实现的时候,我们就可以先定义一个老接口的对象,向这个老接口对象放在适配器模式中,然后就可以调用新接口的函数。

4. 中介者模式

将对个对象间的复杂的关联关系解耦,中介者模式将对个对象间的控制逻辑进行集中管理,变“多个对象相互关联”为“多个对象和一个中介者关联”,简化系统的维护,抵御了可能的变化。

“状态变化”模式

1. 状态模式

一个类它可以有多个状态,当状态不一样的时候,它的每个操作都是不一样的。这种情况可以将与状态相关的操作抽象成一个类,然后每个状态对应一个具体的类去继承这个抽象类。在调用的时候,我们只要用这个抽象类的指针去接收具体类的对象就行。这样有利于状态的扩展。

2. 备忘录模式

在不进行创建备忘录的哪个类的封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态。这样以后就可以将该对象恢复到原先保存的状态。

“数据结构”模式

1. 组合模式

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

比如说对于树节点,它里面的元素可能是两种具体的类型,这两种过程操作的过程是不一样的。这样我们就可以定义一个抽象类,然后定义操作节点的虚函数。两个具体类分别继承这个抽象类。然后节点里面我们放的是抽象类的指针。

2. 迭代器

访问一个聚合对象的内容而无需暴露它的内部表示;为遍历不同的集合结构提供一个统一的接口,从而支持同样的算法在不同的集合结构上进行操作。

3. 职责链

使多个对象都有机会处理请求,从而避免请求的发送者和接受者之间的耦合关系。将这些对象连成一条链,并沿着这条链传递请求,知道有一个对象处理它为止。

“行为变化”模式


1. 命令模式

将行为对象化。这样就可以实现“行为请求者”和“行为实现者”解耦。

2. 访问器

动机:在软件构建过程中,由于需求的改变,某些类层次结构中常常需要增加新的行为(方法),如果直接在基类中做这样的修改,将会给子类带来很繁重的负担,甚至是破坏原有设计。

访问器通过所谓的双重分发(所谓双重分发,就是要进行两次动态的解析。一个是visite类,用户去继承这个类,然后去实现里面的方法,从而动态的添加新的方法。另一个是在visite中,要去访问Elment的每个子类。)来实现在不更改Element类层次结构的前提下,在运行时透明地为类层次结构上的各个类动态添加新的操作。

适用于Element类层次结构稳定,但是里面的操作却面临频繁的改动

“领域规则”模式


解析器

给定一个语言,定义它的文法的一种表示,并定义一种解释器,这个解释器使用该表示来解释语言中的句子。

你可能感兴趣的:(设计模式)