大话设计模式观后感之创建型模式
创建型模式
为什么我们需要创建型模式?
创建型模式隐藏了这些类的实例是如何被创建和放在一起,整个系统关于这些对象所知道的是由抽象类所定义的接口。这样,创建型模式在创建了什么、谁创建它、它是怎么被创建的,以及何时创建这些方面提供了很大的灵活性。
当一个系统应该独立于它的产品创建、构成和表示时,应该考虑用创建性模式。建立相应数目的原型并克隆它们通常比每次用合适的状态手工实例化该类更方便一些
松耦合的理解
这个问题首先要谈谈内聚性与耦合性
内聚性描述的是一个例程内部组成部分之间相互联系的紧密程度。
耦合性描述的是一个例程与其他例程之间联系的紧密程度。
软件开发的目标应该是创建这样的例程:内部完整,也就是高内聚,而与其他例程之间的联系则是小巧、直接、可见、灵活的,这就是松耦合。
如何理解创建型模式存在的意义?
创建型模式抽象了实例化的过程。它们帮助一个系统独立于如何创建、组合和表示它的那些对象。创建型模式都会将关于该系统使用哪些具体的类的信息封装起来。允许客户用结构和功能差别很大的‘产品’对象配置一个系统。配置可以是静态的,即在编译时指定,也可以是动态的,就是运行时再指定。
工厂方法的优势
我觉得她们几位都可能设计出比我更加灵活的代码,但她们的实现也相对就更加复杂。通常设计应该是从工厂方法开始,当设计者发现需要更大的灵活性时,设计便会向其他创建型模式演化。当设计者在设计标准之间进行权衡的时候,了解多个创建型模式可以给设计者更多的选择余地.
简单工厂模式
简单工厂模式是由一个工厂对象决定创建出哪一种产品类的实例。
解决如何实例化对象的问题
不属于23种GOF设计模式之一,不符合开放封闭原则每一次都要修改类。
工厂方法模式
工厂方法模式,定义一个用于创建对象的接口,让子类决定实例化哪一个类。工厂方法使一个类的实例化延迟到其子类。
将实例化方法写在concreteCreator类里面
工厂方法模式和简单工厂的区别:简单工厂模式的最大优点在于工厂类中包含了必要的逻辑判断,根据客户端的选择条件动态实例化相关的类,对于客户端来说,去除了与具体产品的依赖。
缺点:由于每加一个产品,就需要加一个产品工厂的类,增加了额外的开发量。”
通过加分工厂实例化加法运算类
1 | interface IFactory{ |
抽象工厂模式
原版
抽象工厂模式是提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类。
多个产品有一个或多个实现方式,就把同产品系列的抽象。工厂和产品都进行抽象
优点
- 最大的好处便是易于交换产品系列,由于具体工厂类,例如IFactory factory =new AccessFactory().在一个应用中只需要在初始化的时候出现一次,这就使得改变一个应用的具体工厂变得非常容易,它只需要改变具体工厂即可使用不同的产品配置。
- 它让具体的创建实例过程与客户端分离,客户端是通过它们的抽象接口操纵实例,产品的具体类名也被具体工厂的实现分离,不会出现在客户代码中。
缺点修改时需要添加三个类,并需要修改抽象工厂类及抽象工厂子类。
简单工厂来改进
与其用那么多工厂类,不如直接用一个简单工厂来实现,抛弃了IFactory、SqlserverFactory和 AccessFactory三个工厂类,取而代之的是DataAccess类,由于事先设置了db的值(Sqlserver或Access),所以简单工厂的方法都不需要输入参数,这样在客户端就只需要 DataAccess.CreateUser()和 DataAccess.CreateDepartment()来生成具体的数据库访问类实例,客户端没有出现任何一个SOL Server或 Access的字样,达到了解耦的目的。这样就需要在 DataAccess类中每个方法的swicth 中加 case了。
男人的浪漫–反射
Assembly.Load(“程序集名称”).CreateInstance(“命名空间.类名称”)
所有在用简单工厂的地方,都可以考虑用反射技术来去除switch或 if,解除分支判断带来的耦合。
1 | using Syetem.Reflection//引入反射,必须要写 |
单例模式
单例模式(Singleton),保证一个类仅有一个实例,并提供一个访问它的全局访问点。
通常我们可以让一个全局变量使得一个对象被访问,但它不能防止你实例化多个对象。一个最好的办法就是,让类自身负责保存它的唯一实例。这个类可以保证没有其他实例可以被创建,并且它可以提供一个访问该实例的方法。
单线程的实现
Singleton类,定义一个GetInstance操作,允许客户访问它的唯一实例。GetInstance是一个静态方法,主要负责创建自己的唯一实例。
1 | class Singleton{ |
客户端代码
1 | static void Main (string[] args) |
多线程单例
lock 是确保当一个线程位于代码的临界区时,另一个线程不进入临界区。如果其他线程试图进入锁定的代码,则它将一直等待(即被阻止),直到该对象被释放。
双重锁定
1 | class singleton{ |
建造者模式
建造者模式(Builder),将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。
如果我们用了建造者模式,那么用户就只需指定需要建造的类型就可以得到它们,而具体建造的过程和细节就不需知道了。
用处创建一些复杂的对象,这些对象内部构建间的建造顺序通常是稳定的,但对象内部的构建通常面临着复杂的变化。
建造者模式是在当创建复杂对象的算法应该独立于该对象的组成部分以及它们的装配方式时适用的模式。
好处就是使得建造代码与表示代码分离,由于建造者隐藏了该产品是如何组装的,所以若需要改变一个产品的内部表示,只需要再定义一个具体的建造者就可以了。
Product类——产品类,由多个部件组成。
1 | class Product{ |
Builder类——抽象建造者类,确定产品由两个部件 PartA和PartB组成,并声明一个得到产品建造后结果的方法GetResult。
1 | abstract class Builder{ |
ConcreteBuilder1类——具体建造者类。
1 | class ConcreteBuilder1 : Builder{ |
ConcreteBuilder2类——具体建造者类。
1 | class ConcreteBuilder2 :Builder{ |
Director类——指挥者类。
1 | class Director{ |
例子
原型模式
原型模式(Prototype),用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象。
“原型模式其实就是从一个对象再创建另外一个可定制的对象,而且不需知道任何创建的细节。
原版
原型类
1 | abstract class Prototype{ |
具体原型类
1 | class ConcretePrototypel : Prototype{ |
客户端代码
1 | static void Main (string[]args){ |
浅复制和深复制
浅复制,被复制对象的所有变量都含有与原来的对象相同的值,而所有的对其他对象的引用都仍然指向原来的对象。
深复制,深复制把引用对象的变量指向复制过的新对象,而不是原有的被引用的对象。
Csharp更新
.NET在System命名空间中提供了ICloneable接口,其中就是唯一的一个方法Clone(),这样你就只需要实现这个接口就可以完成原型模式了。