常见设计模式整理

设计原则:

设计原则才是最重要的思想,所谓的设计模式只是对设计原则的运用。

1、封装变化:将代码中可能需要变化的地方独立出来,不要和那些不需要变化的代码混在一起。

2、要依赖抽象,不要依赖具体类。(面向抽象编程

3、多用组合,少用继承。

4、尽量不要跨层调用,应当使上层调用下层的,不要让下层调用上层。

5、对扩展开放,对修改关闭。

6、一个类应该只有一个引起变化的原因。

具体的设计模式:

1、策略模式:封装一个算法家族,让他们之间可以互相替换。

给一个算法家族定义一个统一的接口,然后让家族里的每个成员实现这个接口。客服端持有该家族的统一接口而不是具体的实现,这样可以在家族内互相替换。

比如一个计算器,先定义一个计算接口,分别有加减乘除四个具体计算的实现,我们在计算的时候根据运算符号决定使用哪个具体的计算类。通常策略模式跟简单工厂一起使用(记住要封装变化,在这里获取具体的计算类是一个变化点,其他的是不变的)。

2、工厂方法和抽象工厂

简单工厂只是将生产对象这一变化点进行封装。

工厂方法:定义了一个创建对象的接口,但由子类决定要实例化的类是哪一个。

其代码结构图跟策略模式一样,但是两者的作用不一样。策略是为了封装算法,工厂方法是为了实例化不同的对象。而且工厂方法并不一定需要定义一个单独的新接口,就像模版方法一样可以将接口定义在父类中,由子类去完成具体的实现。

抽象工厂:提供一个接口,用于创建相关或依赖对象的家族。

抽象工厂是为了创建一个对象家族而建立的,也就是说同一个抽象工厂的实现类中所生产的对象之间是有某种关联关系的。

比较典型的例子就是配电脑:我们知道主板的cpu插槽和cpu的针脚存在一个匹配的关联关系,这时候我们使用一个抽象工厂方法来保证获取到的主板和cpu是匹配的。

3、观察者模式:定义了对象之间的一对多依赖,这样一来,当一个对象改变状态时,它的所有依赖者都会收到通知并且自动更新。

这个模式比较好理解,具体实现就是定义一个观察者接口和被观察者接口,观察者像被观察者注册时,被观察者持有观察者对象,当被观察者发生变动时,挨个通知观察者。

4、装饰者模式:动态的将责任附加到对象上。

要说到装饰者模式就不能不提java的io,用的io的都知道,一个套一个,有时候会套上很多层,这就是装饰者模式。装饰者模式的实现其实很简单。首先定义一个统一的接口,然后实现一个最基本的底层实现,接着就是装饰者,装饰者同样实现统一的接口,同时持有一个该接口的引用(面向接口编程),装饰者在之前或者之后调用所持有的对象的接口,这样就可以使用装饰者替换掉具体的实现类,完成额外的功能扩展。

5、单例模式:确保一个类这有一个实例,并提供一个全局访问点。

单例模式也比较好理解,使用的时候主要要注意线程同步的问题。它的比较通用的实现是双重null判断,并将第二层的null判断加上同步锁。还有一种是静态内部类获取单例的实例。据说还有一种,是使用枚举实现,这个没有尝试过,有空试试。

6、命令模式:将请求封装成命令接口,命令接口中持有实际执行该动作或一系列动作的对象接口(这些接口并不统一),实现命令接口时实际上是调用各个实际执行对象的实现。

命令模式其实就是在调用者和被调用者之间再插入一层,实现调用者和被调用者之间的解耦。这所以这样做是因为被调用者并不是统一的接口(书中的例子就是有电灯,空调,冰箱等以后其他的电视什么乱七八糟的),如果不加入命令模式的话那么每次更换被调用者都要改变调用者的代码,代价太大,加入命令模式之后,更改被调用者只需要调用调用者的setCommand方法重新设置新的命令即可。

7、适配器模式:将一个类的接口,转换成客户期望的另一个接口。

现在有A和B两个接口,我们有B接口的实现,但是客户调用的是A接口的方法,这时候我们不能去修改客户的接口,同时又不想再重新写一遍A接口的实现,我们可以用一个适配器来解决这个问题。所谓适配器C就是让C实现接口A同时持有一个B接口的引用,当调用C的A接口的方法是实际上是在调用B接口的具体实现。

8、外观模式:定义一个统一的接口,用来访问子系统中的一群接口。

顾名思义就是将一群有关联的接口封装成一个对外的接口,方便外部调用。通常用于一个外部功能需要多步子系统功能才能实现的场景。

9、模版方法模式:在一个方法中定义一个算法的骨架,而将一些步骤延迟到子类中。模版方法使得子类可以在不改变算法结构的情况下,重新定义算法中的某些步骤。

这是我目前用的比较多的一个模式。这个模式的精髓就在于封装相同的流程,并对某些通用子流程提供默认实现,将特定的子流程留给各子类实现。像我们通常对接其他系统的接口的时候,流程无非就是组装参数,获取url,发送请求,解析响应,可以把这几个子流程封装在一个父类的方法里边,让各个子类去实现具体的子流程。

10、迭代器模式:提供一种方法顺序访问一个聚合对象中的各个元素,而又不暴露其内部的表示。

这个模式可以看java的集合类,所有的集合类都实现了Iteratorable接口,这样我们可以对所有的集合类进行统一的读取操作而不用管它具体是哪一种集合类以及它内部的数据结构是什么。

11、组合模式:允许你将对象组合成树形结构来表现“整体/部分”层次结构。组合能让客户以一致的方式处理个别对象以及对象组合。

顾名思义,组合模式是将对象组合成树形结构的,具体的实现方式就是接口中持有一个本身的集合作为该节点的子节点。这里有两种表示方式,一种是树枝节点和叶子节点实现同一个接口,也就是叶子节点也拥有添加子节点和获取子节点的方法,只不过在叶子节点中这两种方法是直接抛出异常而没有具体的实现,这种方式可以让客户端对树枝节点和叶子节点一样的处理。另外一种就是叶子节点和树枝节点实现不同的接口,从接口上就讲两者区分,这样避免了对叶子节点进行获取子节点等操作,但是这样的话客户端就需要认识两种接口。具体使用哪一种方式看自己需要而定。同时组合模式的内部也是一种数据结构,所以一般组合模式会跟迭代器模式一起使用。

12、状态模式:允许对象在内部状态改变时改变它的行为。

状态模式的结构图跟策略模式的结构图基本一样,但是两者的目的不相同。策略模式是单个行为之间的相互替换,而状态模式是每一个状态都得实现主类的所有行为。例如鸭子有三种状态:吃饱、正常、饥饿;有三种行为:飞行、叫、跑;每种行为在每个状态下的表现都不一样,那就意味着每一个状态都要分别实现鸭子的三个行为,这就是状态模式。具体的实现方式是主类持有一个当前状态,主类的具体行为实际调用的是当前状态的行为,每当某种条件达到时主类的当前状态会切换成其他状态以达到更改主类行为的目的。

13、代理模式:为另一个对象提供一个替身或占位符以控制对这个对象的访问。

这个模式跟装饰者模式非常相似,但是同样的,两者的目的不同。装饰者模式的目的是为了改变被装饰类的行为,而代理模式的主要目的是控制对像的访问。可能有人会说结构一样就是一样的模式啊。其实不然,你所要解决的问题决定你使用哪个模式,哪怕他们的结构一摸一样,这一点是必须要明确的。

阅读更多
想对作者说点什么?

博主推荐

换一批

没有更多推荐了,返回首页