大话设计模式读书笔记.docx
《大话设计模式读书笔记.docx》由会员分享,可在线阅读,更多相关《大话设计模式读书笔记.docx(29页珍藏版)》请在冰豆网上搜索。
大话设计模式读书笔记
第一章简单工厂模式
1、代码规范性
A、变量命名规范化
B、if语句逻辑清晰,单向分支逻辑判断应该避免使用重复的if判断
C、异常情况判断
2、面向对象编程
(1)面向对象编程优点:
A、可维护B、可复用C、可扩展D、灵活性好
(2)通过封装、继承、多态将程序耦合性降低,使用设计模式使程序更加灵活,易改,易复用
3、业务封装(将业务逻辑与界面逻辑分开)
(1)低耦合:
高保密,高易维护性。
(2)简单工厂模式
以下为C#代码:
PublicclassOperationFactory
{
PublicstaticOperationCreateOperate(stringoperate)
{
Operationoper=null;
Switch(operate)
{
Case“+”:
oper=newOperationAdd();
Break;
Case“-”:
Oper=newOperationSub();
Break;
Case“*”:
Oper=newOperationMul();
Break;
Case“/”:
Oper=newOperationDiv();
Break;
}
ReturnOper;
}
}
(3)UML类图
*注:
1、“动物”代表类
2、类分三层:
第一层显示类的名称,如是抽象类,用斜体表示;
第二层是类的特性,即字段和属性;
第三层是类的操作,即方法和行为;
3、“+”表示public,“-”表示private,“#”表示protected
4、接口图顶部有<>标注,第一行是接口名称,第二行是接口方法。
5、继承关系用“△”和实线表示,子类指向父类,表示子类继承父类
6、实现接口使用“△”和虚线表示,实现类指向接口,表示类实现了接口
7、类与类关联关系用虚线相连
8、聚合关系(弱拥有关系,拥有者包含被拥有者,但被拥有者不是拥有者不可分割的一部分)使用“◇”+实线箭头(→)表示,聚合体指向单体,表示聚合体由单体聚合成。
聚合体有基数概念,表示几个单体可以聚合成几个聚合体。
9、合成关系(强拥有关系,合成前体与合成体是严格的部分和整体的关系)使用“◆”+实线箭头(→)表示,合成体指向合成前体,表示合成体由合成前体合成。
合成关系有基数概念,表示几个合成前体可以组合成几个合成体。
10、依赖关系,用虚线头“←……”表示,依赖主体指向依赖物,表示依赖主体依赖于依赖物。
第二章策略模式
面向对象编程,并不是类越多越好,类的划分是为了封装,但分类的基础是抽象,具有相同属性和功能的对象的抽象集合才是类。
1、工厂模式的弊端:
仅用于创建对象,对于不断变化的算法维护成本较高。
2、策略模式:
定义了算法家族,分别封装起来,让它们之间可以相互替换,此模式让算法的变化不会影响到使用算法的客户。
以下为C#代码:
//抽象算法类
AbstractclassStrategy
{
//算法方法
PublicabstractvoidAlgorithmInterface();
}
//具体算法A:
ClassConcreateStrategyA:
Strategy
{
//算法A实现方法
PublicoverridevoidAlgorithmInterface()
{
Console.WriteLine(“算法A实现”);
};
//具体算法B
………
}
//Context,用一个ConcreateStrategy类配置,维护一个对Strategy对象的引用。
//上下文
ClassContext
{
StrategyStrategy;
PublicContext(StrategyStrategy)//初始化时,传入具体的策略对象
{
This.strategy=strategy;
}
//上下文接口
PublicvoidContextInterface()//根据具体的策略对象,调用其他算法//的方法
{
Strategy.AlgorithmInterface();
}
}
//客户端代码
StaticvoidMain(string[]args)
{
//由于实例化不同的策略,所以最终在调用Context.ContextInterface()时,所获得的结果就不尽相同。
Contextcontext;
Context=newContext(newConcreateStrategyA());
Context.ContextInterface();
Context=newContext(newConCreateStrategyB());
Context.ContextInterface();
Context=newContext(newConCreateStrategyC());
Context.ContextInterface();
Console.Read();
}
策略模式与工厂模式结合可以有效降低耦合度。
3、
(1)策略模式解析:
策略模式是一种定义一系列算法的方法,从概念上来看,所有这些算法完成的都是相同的工作,只是实现不同,他可以以相同的方式调用所有算法,减少了各种算法类与使用算法类之间的耦合。
(2)策略模式的Strategy类层次为Context定义了一系列可供重用的算法或行为。
继承有助于析取出这些算法中的公共功能。
(3)策略模式的优点:
简化了单元测试,因为每个算法都有自己的类,可以通过自己的接口单独测试。
(4)当不同的行为堆砌在一个类中时,就很难避免使用条件语句来选择合适的行为。
将这些行为封装在一个个独立的Stategy类中,可以在使用这些行为的类中消除条件语句。
(5)策略模式是用来封装算法的,但在实践中,可以用它来封装计划任何类型的规则,只要在分析过程中遇到需要在不同时间应用不同的业务规则,就可以考虑使用策略模式处理这种变化的可能。
第三章单一职责原则
(1)如果一个类承担的职责过多,就等于把这些职责耦合在一起,一个职责的变化可能会削弱或者抑制这个类完成其他职责的能力。
这种耦合会导致脆弱的设计,当变化发生时,设计会遭受到意想不到的破坏。
(2)软件设计正在要做的许多内容,就是发现职责并把那些职责相互分离。
如果你能想到多于一个的动机去改变一个类,那么这个类就具有多于一个的职责,就应该考虑职责分离。
第四章开放—封闭原则(不能开放,但可扩展ocp)
1、开放—封闭原则:
软件实体(类、模块、函数等)应该可以扩展,但是不可修改。
2、无论模块是多么的“封闭”,都会存在一些无法对之封闭的变化。
既然不可能完全封闭,设计人员必须对于他设计的模块应该对哪种变化封闭做出选择。
他必须先猜测出最有可能发生的变化种类,然后构造抽象来隔离那些变化。
3、面对需求,对程序的改动是通过增加新代码进行的,而不是更改现有的代码。
4、在开发工作展开不久就知道可能发生的变化。
查明可能发生的变化所等待的时间越长,要创建正确的抽象就越困难。
5、开放—封闭原则是面向对象设计的核心所在。
遵循这个原则可以带来面向对象技术所声称的巨大好处,也就是可维护、可扩展、可复用、灵活性好。
开发人员应该仅对程序中呈现出频繁变化的那些部分做出抽象,然而,对于应用程序中的每个部分都刻意地进行抽象同样不是好主意。
拒绝不成熟的抽象和抽象本身一样重要。
第五章依赖倒转原则
(1)抽象不应该依赖细节,细节应该依赖于抽象。
(针对接口编程,不要对实现编程)
A、高层模块(扩展的、现实化模块)不应该依赖于低层模块(API,复用的函数如数据库访问函数等)。
两个都应该依赖于抽象。
B、抽象不应该依赖于细节。
细节应该依赖于抽象。
(2)里氏代换原则:
子类型必须能够替换掉它们的父类型。
一个软件实体如果使用的是一个父类的话,那么一定适用于其子类,而且它察觉不出父类对象和子类对象的区别。
也就是说,在软件里面,把父类都替换成它的子类,程序的行为没有变化。
依赖倒转原则(个人理解):
将需求升华到抽象层,即从需求中提取主要内容,摒弃杂质,如外部环境、干扰内容等。
例如,电脑由CPU、内存等构成,则应CPU、内存等作为主要抽象对象,对于其品牌、容量等因素只是具体的实现,不应受其干扰。
(3)依赖倒转是面向对象设计的标志,用哪种语言来编写程序不重要,如果编写时考虑的都是如何针对抽象编程而不是针对细节编程,即程序中所有的依赖关系都是终止于抽象类或者接口,那就是面向对象的设计,反之就是面向过程设计。
第六章装饰模式
动态地给一个对象添加一些额外的职责,就增加功能来说,装饰模式比生成子类更为灵活。
(将所需功能按正确顺序串联起来进行控制)
装饰类实现,以下为C#代码:
Component类
AbstractclassComponent
{
PublicabstractvoidOperation();
}
//ConcreateComponent类
ClassConCreateComponent:
Component
{
PublicoverridevoidOperation()
{
Console.WriteLine(“具体对象的操作”);
}
}
//Decorator类
AbstractclassDecorator:
Component
{
ProtectedComponentcomponent;
PublicvoidSetComponent(Componentcomponent)
{
//形参component设置Component字段
Tponent=component;
}
PublicoverridevoidOperation()
{
//重写Operation(),实际执行的是Component的Operation()
If(component!
=null)
{
Component.Operation();
}
}
}
//ConCreateDecoratorA类
ClassConCreateDecoratorA:
Decorator
{
PrivatestringaddedState;//本类独有功能,以区别于//ConCreateDecoratorB
PublicoverridevoidOperation()
{
//首先运行原Component的Operation(),再执行本类的功能,如//AddedState,相当于对原Component进行了装饰
Base.Operation();
addedState=“NewState”;
Console.WriteLine(“具体装饰对象A的操作”);
}
}
ClassConCreateDecoratorB:
Decorator
{
PublicoverridevoidOperation()
{
//首先运行原Component的Operation(),再执行本类的功能,如//AddedBehavior(),相当于对原Component进行了装饰。
Base.Operation();
AddedBehavior();
Console.WriteLine(“具体装饰对象B的操作”);
}
PrivatevoidAddedBehavior()
{
//本类独有的方法,以区别于ConCreateDecoratorB
}
}
//客户端代码
StaticvoidMain(string[]args)
{
ConCreateComponentc=newConCreateComponent();
ConCreateDecoratorAd1=newConCreateDecoratorA();
ConCreateDecoratorBd2=newConCreateDecoratorB();
//装饰的方法是:
首先用ConCreateComponent实例化对象c,然后用//ConCreateDecoratoraA的实例化对象d1来包装c,再用//ConCreateDecoratorB的对象d2包装d1,最终执行d2的Operation()
D1.SetComponent(c);
D2.SetComponent(d1);
D2.Operation();
Console.Read();
}
注:
如果只有一个ConCreateComponent类而没有抽象的Component类,那么Decorator类可以是ConcreateComponent的一个子类。
同理,如果只有一个ConCreateDecorator类,那么就没有必要建立一个单独的Decorator类,而可以把Decorator和ConCreateDecorator合并成一个类。
装饰模式总结:
(1)装饰模式是为已有功能动态添加更多功能的一种方式。
(2)何时使用:
当系统需要新功能的时候,是向旧的类中添加新的代码。
这些新加的代码通常装饰了原有类的核心职责或主要行为,在主类中加入了新的字段,新的方法和新的逻辑,从而增加了主类的复杂度,而新加入的东西仅仅是为了满足一些只在某种特定情况下才会执行的特殊行为的需要。
而装饰模式却提供了一个非常好的解决方案,它把每个要装饰的功能放在单独的类中,并让这个类包装它所要装饰的对象,因此,当需要执行特殊行为时,客户代码就可以在运行时根据需要有选择地、按顺序地使用装饰功能包装了对象。
第七章代理模式
为其他对象提供一种代理以控制对这个对象的访问。
Subject类定义了RealSubject和Proxy的共用接口.
AbstractClassSubject
{
PublicAbstractvoidRequest();
}
RealSubject类定义proxy所代表的真实实体
ClassRealSubject:
Subject
{
PublicoverridevoidRequest()
{
Console.writeLine(“真实的请求”);
}
}
Proxy类,保存一个引用使得代理可以可以访问实体,并提供与subject相同的接口,使得代理可以代替实体。
classProxy:
Subject
{
RealSubject:
realSubject;
PublicoverridevoidRequest()
{
If(realSubject==null)
realSubject=newRealSubject();
realSubject.Request();
}
}
代理模式应用
1、适用场合:
⑴远程代理:
即为一个对象在不同地址空间提供局部代表。
这样可以隐藏一个对象存在于不同地址空间的事实。
⑵虚拟代理:
根据需要创建开销很大的对象,通过它来存放实例化需要很长时间的真实对象。
⑶安全代理:
用来控制真实对象访问时权限。
⑷智能指引:
当调用真实对象时,代理处理另外一些事。
第八章工厂方法模式
简单工厂模式的最大优点在于工厂类中包含了必要的逻辑判断,根据客户端的选择条件动态实例化相关类,对于客户端来说,去除了与具体产品的依赖。
工厂方法模式:
定义一个用于创建对象的接口,让子类决定实例化哪一个类。
工厂方法使一个类的实例化延迟到其子类。
简单工厂模式不利于扩展,当先前设计的类需要进行扩展时,会导致类必须开放,导致违反开放-封闭原则。
工厂方法模式可以解决该问题。
但是,工厂方法模式仍旧将分支问题留给客户端处理。
第九章原型模式
用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象。
1、原型模式其实就是从一个对象再创建另外一个可定制的对象,而且不需要指定任何创建细节。
2、一般在初始化的信息不发生变化的情况下,克隆是最好的办法。
这既隐藏了对象创建的细节,又大大提高了性能。
以下为C#代码:
//原型类
AbstractclassPrototype
{
Privatestringid;
PublicPrototype(stringid)
{
This.id=id;
}
Publicstringid
{
Get{returnid;}
}
PublicabstractPrototypeClone();//关键方法.C#已提供接口ICloneable,因此//实际应用时不需要该抽象类
}
//具体原型类
ClassConcreatePrototype1:
Prototype
{
PublicConCreatePrototype1(stringid):
base(id)
{
}
PublicoverridePrototypeClone()
{
Return(Prototype)this.MemberwiseClone();//负责对象的数据拷贝
//MemberwiseClone方法的说明:
//创建当前对象的浅表副本。
方法是创建一个新对象,然后将当前的非静态字段//到该新对象。
如果字段是值类型的,则对该字段执行逐位复制。
如果字段是引//型,则复制引用但不复制引用的对象。
因此,原始对象及其副本引用同一对象。
}
}
//客户端代码
StaticvoidMain(string[]args)
{
ConCreatePrototypep1=newConCreatePrototype1(“1”);
ConCreatePrototypec1=(ConCreatePrototype1)p1.Clone();
Console.WriteLine(“Cloned:
{0}”,c1.Id);
Console.Read();
}
3、浅复制与深复制
深复制把引用对象的变量指向复制过的新对象,而不是原有的被引用对象。
第十章模板方法模式
当我们要完成在某一细节层次一致的一个过程或一系列步骤,但其个别步骤在更详细的层次上的实现可能不同时,通常考虑模板模式。
模板方法模式:
定义一个操作中的算法的骨架,而将一些步骤延迟到子类中模板方法使得子类可以不改变一个算法的结构即可重定义该算法的某些步骤。
第十一章迪米特法则
——最少知识原则
如果两个类彼此不必直接通信,那么这两个类不应发生直接的相互作用。
如果其中一个类需要调用另一个类的某一个方法,则通过第三者转发。
迪米特法则前提:
每一个类都应当尽量降低成员的访问权限,保证类之间的松耦合。
类之间的耦合越弱,越有利于复用,一个处在弱耦合的类被修改,不会对有关系的类造成波及。
第十二章外观模式
为子系统中的一组接口提供一个一致的界面,此模式定义了一个高层接口,这个接口使得这一子系统更加容易使用。
以下为C#代码
ClassSubSystemOne
{
PublicvoidMethodOne()
{
Console.WriteLine(“子系统方法一”);
}
}
ClassSubSystemTwo
{
PublicvoidMethodTwo()
{
Console.WriteLine(“子系统方法二”);
}
}
ClassSubSystemThree
{
PublicvoidMethodThree()
{
Console.WriteLine(“子系统方法三”);
}
}
ClassSubSystemFour
{
PublicvoidMethodFour()
{
Console.WriteLine(“子系统方法四”);
}
}
//外观类.Facade
ClassFaçade
{
SubSystemOneOne;
SubSystemTwoTwo;
SubSystemThreeThree;
SubSystemFourFour;
PublicFaçade()
{
One=newSubSystemOne();
Two=newSubSystemTwo();
Three=newSubSystemThree();
Four=newSubSystemFour();
}
PublicvoidMethodA()
{
Console.WriteLine(“\n方法组A()----”);
One.MethodOne();
Two.MethodTwo();
Three.MethodThree();
Four.MethodFour();
}
PublicvoidMethodB()
{
Console.WriteLine(“\n方法组B()-----”);
Two.MethodTwo();
Three.MethodThree();
}
}
//客户端调用代码
Staticvoidmain(string[]args)
{
Façadefaçade=newFacade();
Façade.MethodA();
Façade.MethodB();
Console.Read();
}
何时使用外观模式:
1、设计初期,应有意识地将不同两个层分离,比如将经典三层架构(数据访问层、业务逻辑层、表示层)层与层之间建立外观类,为复杂的子系统提供简单的接口,降低耦合性。
2、开发阶段,子系统往往因为重构演化而变得复杂。
增加外观类可以提供一个简单的接口,减少它们间的依赖。
3、维护大型系统时,为新系统开发一个外观类,来提供设计粗糙或高度复杂的遗留代码的比较清晰简单的接口,让新系统与外观类交互。
第十三章建造者模式
将复杂对象的构建与其表示分离,使得同样的构建过程可以创建不同表示时,使用建造者(生成器)模式。
建造者模式解析:
Builder是为创建一个Product对象的各个部件指定的抽象接口。
ConCreateBuilder是具体建造者,实现Builder接口,构造和装配各个部件。
Director是构建一个使用Builder接口的对象。
何时使用建造者模式:
建造者模式主要用于创建一些复杂的对象,这些对象内部构建间的建造顺序通常是稳定的,但对象内部的构建通常面临着复杂的变化。
因此,若需要改变一个产品的内部表示,只需要再定义一个具体建造者就可以了。
第十四章观察者模式
观察者模式:
定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个对象。
这个主题对象在状态发生变化时,会通知所有观察者对象,使他们能够自动更新自己。
Subject类为抽象通知者,它将所有对观察者对象的引用保存在一个聚集里。
AbstractClassSubject
{
PrivateIListobserv