对各种设计模式的一些思考和总结。
“生成实例”类
单例模式”Singleton”
从名字也很容易理解,只有一个实例。
原理
通过单例模式,我们通常想实现以下效果:
- 确保任何情况下绝对只有1个实例
- 想在程序上表现出“只存在一个实例”
对于不同的编程语言实现“单例模式”的方式也有所不同。对于JAVA,C++这种语言,通常将类的构造函数声明为private,然后提供getInstance()这种静态函数来确保只有一个实例。同时为了保证实例只初始化一次,通常的做法是,加同步锁前后2次判断实例是否已经存在(常见于面试中)。
除此之外,我们还可以利用语言特性实现单例模式,如C#中通过初始化静态变量,python利用模块级对象等等。
实际应用
通常在软件中对一些全局资源工具使用单例,如数据库连接对象,配置文件,日志对象,计数器等等。
UML类图
原型模式Prototype
原理
原型模式和原理和Javascript中的原型模式类似。通常用于以下场景:
- 对象种类繁多,无法将它们整合到一个类中时
- 难以根据类生成实例时
- 想解耦框架与生成的实例时
在Java中,实现原型模式,通过继承Cloneable并重写clone()方法实现原型模式。在其它编程语言中,可能需要我们自己实现相应的接口,需要通过拷贝现有对象的方式实现原型模式。这里需要注意的一个常见问题是深拷贝和浅拷贝的问题,有时候需要我们重写clone方法。
实际应用
- 资源优化场景。
- 类初始化需要消化非常多的资源,这个资源包括数据、硬件资源等。
- 性能和安全要求的场景。
- 通过 new 产生一个对象需要非常繁琐的数据准备或访问权限,则可以使用原型模式。
- 一个对象多个修改者的场景。
- 一个对象需要提供给其他对象访问,而且各个调用者可能都需要修改其值时,可以考虑使用原型模式拷贝多个对象供调用者使用。
- 在实际项目中,原型模式很少单独出现,一般是和工厂方法模式一起出现,通过 clone 的方法创建一个对象,然后由工厂方法提供给调用者。在JAVA语言中,原型模式与 Java 融为浑然一体,大家可以随手拿来使用。
一个典型的应用场景:
试想一下开发一个使用鼠标进行操作的,类似于图形编辑器的应用程序,当用户通过一系列操作创建了一个图形时,如果想再生成一个一模一样的实例,或需要保存图形再还原时,使用已存在的实例来生成实例要简单得多。
UML类图
Builder模式
原理
builder模式通常用于组装具有复杂结构的实例。
比如我们需要构建一篇文档,文档有标题,有正文,还有一些条目。
文档可能是普通文本,也有可能是HTML文本,或者JSON等其它格式。这里就可以使用Builder模式
不同类型的文档生成器是不同的Builder类,它们具有不同实现的标题,正文,条目生成方法,最后可以获取到生成好的文本。我们只需根据需要,就可以生成不同类型的文档对象。
常见应用
当我们需要构建的对象由不同部分组成,可能会有多种不同的表现形式时。
再举一个例子,我们想组装电脑,电脑有组装CPU,内存,硬盘等方法,我们可能日后想组装台式机,笔记本,工作站不同的电脑。这时就可以使用Builder模式。
UML类图
抽象工厂Abstract Factory
原理
理解抽象工厂的关键在于有2种抽象,抽象零件和抽象产品。抽象工厂的作用就是将抽象零件组装成抽象产品。和刚刚讲的Builder模式有些类似,都是用于生成复杂的实例。
既然都是抽象的,那么我们并不关心零件的具体实现,而是只关心接口。我们仅使用该接口将零件组装成产品。
常见应用
设想有一个生成电视的工厂,生产电视需要面板,遥控器,CPU等零件。
这个电视工厂就是抽象工厂,这些零件就是抽象零件。
可以有不同的具体工厂实现,一个生产节能型电视,一个生产智能型电视。那么它们可能需要的具体零件就不一样,节能型电视工厂需要使用节能型的零件,智能型电视工厂需要使用智能型的零件。这就是一个典型的抽象工厂模式的应用。
UML类图
适应型设计模式
迭代器模式:Iterator模式
原理
迭代器模式比较好理解,当我们需要对一个聚合型对象进行遍历时,可以使用这个对象的迭代器进行遍历,这样做的好处时,聚合型对象的实际存储结构可以任意,我们只需要关注迭代器的接口即可。
典型的迭代器一般都具有hasNext和next方法,分别用于判断是否结束和获取下一个对象。
UML类图
Adapter模式:适配器模式
原理
关于适配器模式,生活中的一个典型例子就是变压器或着转接头。把一种接口适配成为我们希望的接口。
适配器模式的实现通常有2种:
- 类适配器模式(使用继承)
- 对象适配器(使用委托)
常见应用
使用现成代码:当我们要使用一个现成的代码,而现成代码的接口和我们期望的不一致时。
版本升级兼容:当我们希望升级一个接口,而又要同时保证使用旧接口的程序时,可以编写一个新接口到旧接口的适配器,这样就只需要维护新代码。
UML类图
- 使用继承
- 使用委托