工厂方法模式:提供一个简单的决策类,根据条件生成产品。
抽象工厂模式:提供一个创建并返回一系列产品的接口。
单件模式:某个类只能有一个实例。提供一个全局访问点。(可拓展到有限个实例)
生成器模式:将一个复杂对象的构建于呈现分开,以便根据不同需要创建不同的形式。
原型模式:先实例化一个类,然后克隆或者拷贝该类来构建新的实例。可以用共有方法进一步修改这些实例。
难点:抽象工厂模式与生成器模式的比较
简单工厂模式:专门定义一个类来负责创建其他类的实例,被创建的实例通常都具有共同的父类。它又称为静态工厂方法模式,属于类的创建型模式。
简单工厂模式的实质是由一个工厂类根据传入的参数,动态决定应该创建哪一个产品类(这些产品类继承自一个父类或接口)的实例。
意图:提供一个类,由它负责根据一定的条件创建某一具体类的实例
角色及其职责:
模式的特点:
工厂方法模式: 工厂方法模式的对简单工厂模式进行了抽象。有一个抽象的Factory类(可以是抽象类和接口),这个类将不在负责具体的产品生产,而是只制定一些规范,具体的生产工作推延到其子类去完成。
意图:定义一个用户创建对象的接口,让子类决定实例化哪一个类,工厂方法模式使一个类的实例化延迟到其子类。
优点:实现了开闭原则,可以在不改变工厂的前提下增加新产品。
实现要点:
效果:
适用性:
附注:
抽象工厂模式:提供创建对象的接口。与工厂方法类似,但此处返回的一系列相关产品。实现过程同样推延到子系列类去实现。与工厂方法的区别在于他们的层次模型。工厂方法的抽象基类只有儿子,而抽象工厂模式却是有孙子,而且每个儿子的儿子们之间有相互关联依赖关系。
意图:提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类。
角色及职责:
附注:简单工厂、工厂方法、抽象工厂比较
简单工厂,工厂方法,抽象工厂都属于设计模式中的创建型模式。其主要功能都是帮助我们把对象的实例化部分抽取了出来,优化了系统的架构,并且增强了系统的扩展性。
小结:
区别:
以上三种工厂方法在等级结构和产品族这两个方向上的支持程度不同。所以要根据情况考虑应该使用哪种方法。
意图:单件模式保证应用只有一个全局惟一的实例,并且提供一个访问它的全局访问点。
结构:包括防止其他对象创建实例的私有构造函数、保存惟一实例的私有变量和全局访问接口等。
效果:单件提供了全局惟一的访问入口,因此易于控制可能发生的冲突。单件是对类静态函数的一种改进,首先它避免了全局变量对系统的污染;其次正常类可以有子类,可以定义虚函数,具有多态性。而类中的静态方法是不能定义为虚函数的,因此不具有多态性。单件模式可以扩展为多件,即允许有受控的多个实例存在。
适用场合:当类只能有一个实例存在,并且可以在全局访问时。这个惟一的实例应该可以通过子类实现扩展,并且用户无须更改代码即可使用。我们前面介绍的工厂类经常被实例化为全局惟一的单件,可能的单件还有管理日志的对象、关键字生成对象和外部设备接口对象等。
实现:
比较:
实现:
public sealed class Singleton
{
static Singleton instance=null;
Singleton()
{
}
public static Singleton Instance
{
get
{
if (instance==null)
{
instance = new Singleton();
}
return instance;
}
}
}
这种方式的实现对于线程来说并不是安全的,因为在多线程的环境下有可能得到Singleton类的多个实例。如果同时有两个线程去判断(instance == null),并且得到的结果为真,这时两个线程都会创建类Singleton的实例,这样就违背了Singleton模式的原则。实际上在上述代码中,有可能在计算出表达式的值之前,对象实例已经被创建,但是内存模型并不能保证对象实例在第二个线程创建之前被发现。
该实现方式主要有两个优点:
public sealed class Singleton
{
static Singleton instance=null;
static readonly object padlock = new object();
Singleton()
{
}
public static Singleton Instance
{
get
{
lock (padlock)
{
if (instance==null)
{
instance = new Singleton();
}
return instance;
}
}
}
}
这种方式的实现对于线程来说是安全的。我们首先创建了一个进程辅助对象,线程在进入时先对辅助对象加锁然后再检测对象是否被创建,这样可以确保只有一个实例被创建,因为在同一个时刻加了锁的那部分程序只有一个线程可以进入。这种情况下,对象实例由最先进入的那个线程创建,后来的线程在进入时(instence == null)为假,不会再去创建对象实例了。但是这种实现方式增加了额外的开销,损失了性能。
public sealed class Singleton
{
static Singleton instance=null;
static readonly object padlock = new object();
Singleton()
{
}
public static Singleton Instance
{
get
{
if (instance==null)
{
lock (padlock)
{
if (instance==null)
{
instance = new Singleton();
}
}
}
return instance;
}
}
}
这种实现方式对多线程来说是安全的,同时线程不是每次都加锁,只有判断对象实例没有被创建时它才加锁,有了我们上面第一部分的里面的分析,我们知道,加锁后还得再进行对象是否已被创建的判断。它解决了线程并发问题,同时避免在每个Instance 属性方法的调用中都出现独占锁定。它还允许您将实例化延迟到第一次访问对象时发生。实际上,应用程序很少需要这种类型的实现。大多数情况下我们会用静态初始化。这种方式仍然有很多缺点:无法实现延迟初始化。
public sealed class Singleton
{
static readonly Singleton instance=new Singleton();
static Singleton() //只要调用类名就调用.注意此处static前面不可以加权限修饰符。且该构造函数只在第一次引用该类成员的时候调用(参见msdn中关于金泰构造函数讲解部分)
{
}
Singleton()
{
}
public static Singleton Instance
{
get
{
return instance;
}
}
}
看到上面这段富有戏剧性的代码,我们可能会产生怀疑,这还是Singleton模式吗?在此实现中,将在第一次引用类的任何成员时创建实例。公共语言运行库负责处理变量初始化。该类标记为 sealed 以阻止发生派生,而派生可能会增加实例。此外,变量标记为 readonly,这意味着只能在静态初始化期间(此处显示的示例)或在类构造函数中分配变量。
该实现与前面的示例类似,不同之处在于它依赖公共语言运行库来初始化变量。它仍然可以用来解决 Singleton 模式试图解决的两个基本问题:全局访问和实例化控制。公共静态属性为访问实例提供了一个全局访问点。此外,由于构造函数是私有的,因此不能在类本身以外实例化 Singleton 类;因此,变量引用的是可以在系统中存在的唯一的实例。
由于 Singleton 实例被私有静态成员变量引用,因此在类首次被对 Instance 属性的调用所引用之前,不会发生实例化。
这种方法唯一的潜在缺点是,您对实例化机制的控制权较少。在 Design Patterns 形式中,您能够在实例化之前使用非默认的构造函数或执行其他任务。由于在此解决方案中由 .NET Framework 负责执行初始化,因此您没有这些选项。在大多数情况下,静态初始化是在 .NET 中实现 Singleton 的首选方法。
public sealed class Singleton
{
Singleton()
{
}
public static Singleton Instance
{
get
{
return Nested.instance;
}
}
class Nested
{
static Nested()
{
}
internal static readonly Singleton instance = new Singleton();
}
}
这里,初始化工作有Nested类的一个静态成员来完成,这样就实现了延迟初始化,并具有很多的优势,是值得推荐的一种实现方式。
实现要点:
优点 :
缺点 :
适用性 :
生成器模式:在软件设计中,有时候面临着一个非常复杂的对象的创建工作。这个复杂的对象通常可以分成几个较小的部分,由各个子对象组合出这个复杂对象的过程相对来说比较稳定,但是子对象的创建过程各不相同并且可能面临变化。根据OOD中的OCP原则,我们自然应该对这些子对象的创建过程进行变化封装。这就是生成器模式的思路。定义一个抽象的建造者的角色(Builder),规定所有具体的建造者都应该具有的功能——这些功能就是如何创建复杂对象的某个特定部分(子对象),而具体如何创建子对象有具体的创建者实现。再定义一个指导者的角色,它把创建者作为工具,知道如何使用这个工具来创建复杂对象。这样,客户在需要创建这个复杂对象的时候,只需要给指导者一个具体的创建者就可以了。至于具体创建者如何创建子对象的细节以及这些子对象之间的差异,不是指导者,也不是客户关心的。
意图:将一个复杂的构建与其表示相分离,使得同样的构建过程可以创建不同的表示(GoF)。
角色及指责:
适用范围:生成器模式用于分步骤构建一个复杂的对象,如何划分步骤是一个稳定的算法,而复杂对象的各个部分的创建过程则经常变化。通过把各部件的创建过程封装到生成器中,使得复杂对象的创建过程和最终表象实现分分离。使用生成器模式,隐藏了具体产品的表示方法、内部结构和装配过程。通过定义一个新的生成器,就可以改变产品的内部表示。生成器模式中的指导者角色控制着生成器生成部件的过程。因此,通过指导者,可以实现对复杂产品生成步骤进行精细的控制——这一点在复杂产品部件的生成必须遵循一定的次序时显得十分方便。
优点:采用生成器模式可以轻松地改变产品的内部表示。生成器模式将构造代码和表示代码分开。构造过程可以更精细地控制,生成器模式强调的是产品的构造过程,产品各部分具有依赖关系非常重要。需要注意的是,不同生成器产生的对象可能不属于同一类型,因此使用生成器的客户必须知道产品的具体类型。这意味着生成器经常不能互换,不同的生成器针对的客户程序也不相同。
附注:与抽象工厂模式的比较
生成器模式关注于将构造对象的过程和构造的各个部分分开,而抽象工厂关注于构建一个产品系列。实际上,最大的区别是生成器模式创建的产品不一定有共同的父类,只要有类似的构造过程即可。实际上我们常见到的文件资源管理器的实现完全可以使用生成器模式。
生成器模式和工厂模式很相象,但是它们有很明显的区别。那就是工厂模式只是根据给的参数不同,工厂"生产"并返回不同的对象。生成器模式除了根据不同参数"生产"不同对象外,这些不同的对象还包含着不同的数据。生成器模式比工厂模式复杂就复杂在多"数据"这一部分。
注意问题:
原型模式:
定义:用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象。Prototype模式允许一个对象再创建另外一个可定制的对象,根本无需知道任何如何创建的细节,工作原理是:通过将一个原型对象传给那个要发动创建的对象,这个要发动创建的对象通过请求原型对象拷贝它们自己来实施创建。
——————————————————————————————————————
意图:用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象。
角色及职责:
优点:引入Prototype模式后不再需要一个与具体产品等级结构平行的工厂方法类,减少了类的构造,同时客户程序可以在运行时刻建立和删除原型(自定义界面时,此点尤其重要)。
要实现深拷贝,可以通过序列化的方式。抽象类及具体类都必须标注为可序列化的[Serializable]
实现要点:
效果:
适用性:
附注:
Prototype模式同工厂模式,同样对客户隐藏了对象的创建工作,但是,与通过对一个类进行实例化来构造新对象不同的是,原型模式是通过拷贝一个现有对象生成新对象的,达到了"隔离类对象的使用者和具体类型(易变类)之间的耦合关系"的目的。
此处引入的知识点式浅拷贝与深拷贝的问题:
概念:
a.浅拷贝(Shallow Copy影子克隆):只复制对象的基本类型,对象类型,仍属于原来的引用。
b.深拷贝(Deep Copy 深度克隆):不紧复制对象的基本类,同时也复制原对象中的对象.完全产生新对象。
实现机制:
2.深拷贝与浅拷贝实现机制:
对于值类型:
a.浅拷贝: 通过赋值等操作直接实现,将对象中的值类型的字段拷贝到新的对象中。
b.深拷贝:通过赋值等操作直接实现,将对象中的值类型的字段拷贝到新的对象中。 和浅拷贝相同
对于引用类型:
a.浅拷贝: MemberwiseClone 方法创建一个浅副本,方法是创建一个新对象,如果字段是值类型的,则对该字段执行逐位复制。如果字段是引用类型,则复制引用原始对象,与原对象引用同一对象。
b.深拷贝:拷贝对象应用,也拷贝对象实际内容,也就是创建了一个新的改变新对象 不会影响到原始对象的内容
这种情况需要为其实现ICloneable接口中提供的Clone方法。
差别就是在对于引用类型的实现深拷贝和浅拷贝的时候的机制不同,前者是MemberwiseClone 方法实现,后者是通过继承实现ICloneable接口中提供的Clone方法,实现对象的深拷贝。