本文共 9427 字,大约阅读时间需要 31 分钟。
我们来一起回顾一下做个小结:
什么是设计模式?
设计模式(Design pattern)是一套被反复使用、多数人知晓的、经过分类编目的、代码设计经验的总结。
每一个模式描述了一个在我们周围不断重复发生的问题,以及该问题的解决方法的核心。
为什么需要使用设计模式?
使用设计模式是为了可重用代码、让代码更容易被他人理解、保证代码可靠性。简单来说,使用设计模式可以让我们不必做一些不必要的重复的工作。
一般来说,一个模式都有四个基本要素:
1.模式名称:一个助记名,用一两个词来描述模式的问题、解决方案和效果。简单来说就是设计模式的名称。
2.问题:问题的描述有助于我们判断在何时使用设计模式。
3.解决方案:模式就像一个模板,设计模式的组成部分,它们之间的相互关系及各自的职责和问题存在的前因后果,可能描述了特定的设计问题。比如怎样恋情对象表示算法。
4.效果:设计模式对系统的灵活性、扩充性、或可移植性的影响。
创建型模式有哪些?
1.单例模式:保证一个类仅有一个实例,并提供一个访问它的全局访问点。保证没有其他实例可以被创建,并且它可以提供一个访问该实例的方法。
简单点讲单例模式就是确保一个类只有一个实例,并且该实例是自动创建,并可以向整个系统提供该实例,客户端只能调用一个公共接口来产生一个实例,而且只能产生一次。
单例模式:
意图:单件模式保证应用只有一个全局惟一的实例,并且提供一个访问它的全局访问点。
结构:包括防止其他对象创建实例的私有构造函数、保存惟一实例的私有变量和全局访问接口等。
效果:单件提供了全局惟一的访问入口,因此易于控制可能发生的冲突。单件是对类静态函数的一种改进,首先它避免了全局变量对系统的污染;其次正常类可以有子类,可以定义虚函数,具有多态性。而类中的静态方法是不能定义为虚函数的,因此不具有多态性。单件模式可以扩展为多件,即允许有受控的多个实例存在。
适用场合:当类只能有一个实例存在,并且可以在全局访问时。这个惟一的实例应该可以通过子类实现扩展,并且用户无须更改代码即可使用。我们前面介绍的工厂类经常被实例化为全局惟一的单件,可能的单件还有管理日志的对象、关键字生成对象和外部设备接口对象等。
实现:
比较:
实现要点:
优点 :
缺点 :
适用性 :
该实现方式主要有两个优点:
2.工厂方法模式:定义一个用于创建对象的接口。让子类决定实例化具体哪一个类。工厂模式使一个类的实例化延迟到其子类。
工厂方法模式:
专门定义一个类来负责创建其他类的实例,被创建的实例通常都具有共同的父类。它又称为静态工厂方法模式,属于类的创建型模式。
简单工厂模式的实质是由一个工厂类根据传入的参数,动态决定应该创建哪一个产品类(这些产品类继承自一个父类或接口)的实例。
意图:提供一个类,由它负责根据一定的条件创建某一具体类的实例
角色及其职责:
模式的特点:
工厂方法模式的对简单工厂模式进行了抽象。有一个抽象的Factory类(可以是抽象类和接口),这个类将不在负责具体的产品生产,而是只制定一些规范,具体的生产工作推延到其子类去完成。
意图:定义一个用户创建对象的接口,让子类决定实例化哪一个类,工厂方法模式使一个类的实例化延迟到其子类。
优点:实现了开闭原则,可以在不改变工厂的前提下增加新产品。
实现要点:
效果:
适用性:
附注:
3.抽象工厂模式:提供一个创建一系列相关或者相互依赖对象的接口,且无需指定它们具体的类。
抽象工厂模式:
提供创建对象的接口。与工厂方法类似,但此处返回的一系列相关产品。实现过程同样推延到子系列类去实现。与工厂方法的区别在于他们的层次模型。工厂方法的抽象基类只有儿子,而抽象工厂模式却是有孙子,而且每个儿子的儿子们之间有相互关联依赖关系。
意图:提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类。
角色及职责:
附注:简单工厂、工厂方法、抽象工厂比较
简单工厂,工厂方法,抽象工厂都属于设计模式中的创建型模式。其主要功能都是帮助我们把对象的实例化部分抽取了出来,优化了系统的架构,并且增强了系统的扩展性。
小结:
区别:
以上三种工厂方法在等级结构和产品族这两个方向上的支持程度不同。所以要根据情况考虑应该使用哪种方法。
抽象工厂和工厂方法区别:
抽象工厂模式与建造者模式比较
4.建造者模式:将一个复杂对象的构建与它的表示相分离,使得同样的构建过程可以创建不同的表示。
可以这么理解:建造者模式就是在抽象工厂模式上加了组装类,这个组装类负责将一系列与之有相互关系的产品进行组装,这个组装类负责调用具体工厂类创建产品的方法,将产品创建并组装好,然后客户端直接调用这个组装类来生产一个整体的产品。
比如:创建奥迪汽车的轮胎、发动机、底盘、车身,也要创建BMW汽车的轮胎、发动机、底盘、车身,
在建造者模式下,有抽象工厂模式下的所有抽象类和具体类的同时,多了一个组装类,这个组装类调用具体工厂类创建部件,并把部件进行组合最终将结果返回给客户端。
建造者模式:
作用:将一个复杂对象构建与其表示分离,使得同样的构建过程可以创建不同的表示。
个人理解:在Builder抽象类中定义创建对象不同表示所需的抽象方法(这个可以说是这个模式的根基),在Builder子类中实现需要的方法,以提供对象不同的表示(即:对象属性的不同,不知道这么说对不对)。在Director类(该类是本模式的入口,其接受Builder抽象类参数)中通过Builder抽象类中抽象方法的组合调用,来实现创建同一对象的不同表示。这里可通过两方面进行扩展,一个是Builder子类实现的添加。二是Director类中添加不同的对象表示方式或提供不同的Director类。
AbstractFactory 和 Builder相似,因为它也可以创建复杂对象。主要的区别是Builder模式着重于一步步构造一个复杂对象。而Abstract Factory着重于多个系列的产品对象(简单的或是复杂的)。Bulider在最后的一步返回产品,而对于Abstract Factory来说,产品是立即返回的。
在软件设计中,有时候面临着一个非常复杂的对象的创建工作。这个复杂的对象通常可以分成几个较小的部分,由各个子对象组合出这个复杂对象的过程相对来说比较稳定,但是子对象的创建过程各不相同并且可能面临变化。根据OOD中的OCP原则,我们自然应该对这些子对象的创建过程进行变化封装。这就是生成器模式的思路。定义一个抽象的建造者的角色(Builder),规定所有具体的建造者都应该具有的功能——这些功能就是如何创建复杂对象的某个特定部分(子对象),而具体如何创建子对象有具体的创建者实现。再定义一个指导者的角色,它把创建者作为工具,知道如何使用这个工具来创建复杂对象。这样,客户在需要创建这个复杂对象的时候,只需要给指导者一个具体的创建者就可以了。至于具体创建者如何创建子对象的细节以及这些子对象之间的差异,不是指导者,也不是客户关心的。
意图:将一个复杂的构建与其表示相分离,使得同样的构建过程可以创建不同的表示(GoF)。
角色及指责:
适用范围:生成器模式用于分步骤构建一个复杂的对象,如何划分步骤是一个稳定的算法,而复杂对象的各个部分的创建过程则经常变化。通过把各部件的创建过程封装到生成器中,使得复杂对象的创建过程和最终表象实现分分离。使用生成器模式,隐藏了具体产品的表示方法、内部结构和装配过程。通过定义一个新的生成器,就可以改变产品的内部表示。生成器模式中的指导者角色控制着生成器生成部件的过程。因此,通过指导者,可以实现对复杂产品生成步骤进行精细的控制——这一点在复杂产品部件的生成必须遵循一定的次序时显得十分方便。
优点:采用生成器模式可以轻松地改变产品的内部表示。生成器模式将构造代码和表示代码分开。构造过程可以更精细地控制,生成器模式强调的是产品的构造过程,产品各部分具有依赖关系非常重要。需要注意的是,不同生成器产生的对象可能不属于同一类型,因此使用生成器的客户必须知道产品的具体类型。这意味着生成器经常不能互换,不同的生成器针对的客户程序也不相同。
附注:与抽象工厂模式的比较
生成器模式关注于将构造对象的过程和构造的各个部分分开,而抽象工厂关注于构建一个产品系列。实际上,最大的区别是生成器模式创建的产品不一定有共同的父类,只要有类似的构造过程即可。实际上我们常见到的文件资源管理器的实现完全可以使用生成器模式。
生成器模式和工厂模式很相象,但是它们有很明显的区别。那就是工厂模式只是根据给的参数不同,工厂"生产"并返回不同的对象。生成器模式除了根据不同参数"生产"不同对象外,这些不同的对象还包含着不同的数据。生成器模式比工厂模式复杂就复杂在多"数据"这一部分。
注意问题:
5.原型模式:用原型实例指定创建对象的种类,并通过拷贝这些原型创建新的对象。
简单说就是通过一个原型对象来表明要创建对象的类型,然后使用复制这个原型对象的方法来创建更多同类型的对象,在原型模式中可以动态地添加产品类,而且对整体结构没有影响。
比如:我要生产一辆汽车,那么在流水线上会有一道工序是组装车身,然后第二道工序是在第一道工序的基础上(一个车身原型)加上一个轮胎,
第三道工序在第二道工序上增加发动机,以此类推,每一道工序完成后产生了一个原型,下一道工序是相当于拷贝了前一道工序的结果原型,并在这个基础上再加上部件。
原型模式:
工作原理:通过将一个原型对象传给那个要发动创建的对象,这个要发动创建的对象通过请求原型对象拷贝它们自己来实施创建。
——————————————————————————————————————
意图:用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象。
角色及职责:
优点:引入Prototype模式后不再需要一个与具体产品等级结构平行的工厂方法类,减少了类的构造,同时客户程序可以在运行时刻建立和删除原型(自定义界面时,此点尤其重要)。
要实现深拷贝,可以通过序列化的方式。抽象类及具体类都必须标注为可序列化的[Serializable]
实现要点:
效果:
适用性:
附注:
Prototype模式同工厂模式,同样对客户隐藏了对象的创建工作,但是,与通过对一个类进行实例化来构造新对象不同的是,原型模式是通过拷贝一个现有对象生成新对象的,达到了"隔离类对象的使用者和具体类型(易变类)之间的耦合关系"的目的。
此处引入的知识点式浅拷贝与深拷贝的问题:
概念:
a.浅拷贝(Shallow Copy影子克隆):只复制对象的基本类型,对象类型,仍属于原来的引用。 b.深拷贝(Deep Copy 深度克隆):不紧复制对象的基本类,同时也复制原对象中的对象.完全产生新对象。
实现机制:
2.深拷贝与浅拷贝实现机制:
对于值类型: a.浅拷贝: 通过赋值等操作直接实现,将对象中的值类型的字段拷贝到新的对象中。 b.深拷贝:通过赋值等操作直接实现,将对象中的值类型的字段拷贝到新的对象中。 和浅拷贝相同
对于引用类型: a.浅拷贝: MemberwiseClone 方法创建一个浅副本,方法是创建一个新对象,如果字段是值类型的,则对该字段执行逐位复制。如果字段是引用类型,则复制引用原始对象,与原对象引用同一对象。
b.深拷贝:拷贝对象应用,也拷贝对象实际内容,也就是创建了一个新的改变新对象 不会影响到原始对象的内容 这种情况需要为其实现ICloneable接口中提供的Clone方法。
差别就是在对于引用类型的实现深拷贝和浅拷贝的时候的机制不同,前者是MemberwiseClone 方法实现,后者是通过继承实现ICloneable接口中提供的Clone方法,实现对象的深拷贝。
根据两条准则类创建模式和对象创建模式将23种设计模式进行分类,如下图