大话设计模式

UML

  • 类:抽象类用斜体表示
  • 接口:<> 或者棒棒糖表示法
  • 继承:空心三角形+实线
  • 实现:空心三角形+虚线
  • 关联:当一个类知道另一个类时,可以用关联,实线箭头
  • 聚合:表示一种弱的“拥有”关系,体现的是A对象可以包含B对象,但B对象不是A对象的一部分,空心的菱形+实线箭头
  • 合成:表示一种强的“拥有”关系,体现了严格的部分和整体关系,部分和整体的生命周期一样,实心的菱形+实心箭头
  • 依赖:虚线箭头

创建型

社会化的分工越来越细,自然在软件设计方面也是如此,因此对象的创建和对象的使用分开也就成为了必然趋势。因为对象的创建会消耗掉系统的很多资源,所以单独对对象的创建进行研究,从而能够高效地创建对象就是创建型模式要探讨的问题。这里有6个具体的创建型模式可供研究,它们分别是:

简单工厂模式

如何去实例化对象的问题,考虑用一个单独的类来做这个创建实例的过程(该工厂类中多有switch或if结构来接受用户输入的参数,进而实例化不同的实例返回)
所有在用到简单工厂的地方,都可以考虑反射来去除switch或if,解决分支判断带来的耦合。(反射可以利用字符串来实例化对象,而变量是可以更换的 — 反射 + 配置文件)
Tips:新修改来时,除了创建必要的子类之外,还需要修改简单工厂类,对修改开放。不需要修改客户端(传入的参数改变而已)

工厂方法模式

FactoryMethod 定义一个用于创建对象的接口,让子类决定实例化哪一个类。工厂方法使一个类的实例化延迟到其子类。
与简单工厂的区别:简单工厂类派生了很多子工厂 ,每个工厂子类类(有共同的父类)对应于一个实例的初始化过程。因此原来在简单工厂类中switch和if结构被去除。只需要在客户端中创建指定的工厂来实例化指定的类即可。
Tips:工厂方法模式实现时,客户端需要决定实例化哪一个工厂来实现运算类,选择判断的问题还是存在的,只是工厂方法把简单工厂的内部逻辑判断移到了客户端代码来进行,你想加功能,本来是改工厂类的,而现在是修改客户端

抽象工厂 方法模式

Abstract Factory 提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类
与工厂方法的区别:每个工厂类(有共同的父类工厂)处理的对象多于一个时,即每个工厂子类中要实例化多于一个的对象时。
Tips:抽象工厂方法模式非常便于交换产品系统;客户端通过它们的抽象接口操作实例,产品的具体类名也被具体工厂的实现分离,不会出现在客户代码中

单例模式

Singleton 保证一个类仅有一个实例,并提供一个访问它的全局访问点
所有类都有构造方法,不编码则系统默认生成空的构造方法,若有显示的构造方法,默认的构造方法就会失效。若把类的构造方法写成private的,那么外部程序就不能用new来实例化它了
Tips:因为Singleton类封装它的唯一实例,这样它可以严格控制客户怎样访问它以及何时访问它,简单地说就是对唯一实例的受控访问。

建造者模式

Builder 将一个复杂对象的构建与它的表示分离,使得同样的构造过程可以创建不同的表示
创建的过程是人稳定的,而具体创建的细节是不同的(小人 vs 胖小人),使用了该模式以后,用户只需要指定的需要创建的类型就可以得到他们,而具体建造的过程和细节就不需要知道了。
Tips:当创建复杂对象的算法应该独立于该对象的组成部分以及它们的装配方式时适用,好处是使得建造代码与表示代码分离,由于建造者隐藏了该产品是如何组装的,所以或需要改变一个产品的内部表示,只需要再定义一个具体的建造者就可以了。

原型模式

Prototype 用原型实例指定创建对象的类型,并且通过拷贝这些原型创建新的对象(JAVA 与 .NET都有对应的接口实现)
从一个对象再创建另外一个可定制的对象,而且不需要知道任何创建的细节。
一般在初始化的信息不发生改变的情况下,克隆是最好的方法,这既隐藏了对象创建的细节,又对性能是大的提高。它相当于不用重新初始化对象,而是动态的获得对象的运行时的状态。
(浅复制:被复制的对象的所有变量都含有与原来的对象相同的值,而所有的对其它对象的引用都仍然指向原来的对象)
(深复制:与上面的区别在于,深复制把引用对象的变量指向复制过的新对象,而不是原有的被引用的对象)
Tips:当创建实例的过程非常昂贵时适用