设计模式学习总结一.docx
《设计模式学习总结一.docx》由会员分享,可在线阅读,更多相关《设计模式学习总结一.docx(28页珍藏版)》请在冰豆网上搜索。
![设计模式学习总结一.docx](https://file1.bdocx.com/fileroot1/2023-2/2/1acadde4-2881-4cc1-bb0b-060adbe7f963/1acadde4-2881-4cc1-bb0b-060adbe7f9631.gif)
设计模式学习总结一
前言:
推荐几本相关的书:
(1)HeadFirstDesignPatterns
曾经买HeadFirst系列的时候买的一本书,是java语言的案例,但是完全不影响你了解设计模式。
这系列的书就是有很多图,做快速了解建议买。
(2)大话设计模式
1个月前买的,看作者简介是名老师,里面就是菜鸟和大鸟的对话举出很多例子,案例也相当不错。
这本书最起码让我感觉特别不错。
(3)重构与模式
这本是必须要看的一本书,前几张讲了什么是重构,什么是模式。
然后两者之间的关系。
后边是是讲设计模式的动机,做法,实例,变体。
也不分什么创建,行为,结构什么的。
最后一章是重构的实现。
一.设计原则
单一职责原则告诉我们实现类要职责单一;里氏替换原则告诉我们不要破坏继承体系;依赖倒置原则告诉我们要面向接口编程;接口隔离原则告诉我们在设计接口的时候要精简单一;迪米特法则告诉我们要降低耦合。
而开闭原则是总纲,他告诉我们要对扩展开放,对修改关闭。
1.开闭原则OCP(Open-ClosePrinciple)
【开指的是对扩展开放,关指的对修改关闭。
】
我把它理解为“一国两制”原则。
一国两制怎么说:
香港澳门继承了中国这个类,表示说:
一个中国不可改变,但针对与港澳实际情况,他们实行的是资本主义经济。
2.单一职责原则RRP(SingleResponsibilityPrinciple)
【一个类应该只有一个发生变化的原因。
】
高内聚低耦合这就是我们写程序的目标,但是很多时候高耦合会在不经意间就产生了,这大多是因为职责扩散造成的。
这个原则最好理解,又最容易违背这个原则。
原因就是职责这个家伙不好确认。
3.依赖倒转原则DIP(DependencyInversionPrinciple)
【抽象不应当依赖于细节,细节应当依赖于抽象;高层实现不依赖底层实现。
】想想让你封装一个类的时候你首先会做什么。
会先封装接口,再写实现。
{#总工说这样处理才是合理的。
原因就在这#}。
面向接口编程而非实现。
这个原则在我看来也是面向对象设计的标志。
举个例子:
usb是不是所有的的电脑都能通过usb接口连接。
如果联想的usb接口和苹果的usb接口不一样,那么你买了一个200多的USB键盘,结果是不是就不能公用了。
4.里氏代换原则LiskovSubsitutionPrinciple(LSP)
【子类可以扩展父类的功能,但不能改变父类原有的功能】
里氏代换原则是对“开-闭”原则的补充。
实现“开-闭”原则的关键步骤就是抽象化。
而基类与子类的继承关系就是抽象化的具体实现,所以里氏代换原则是对实现抽象化的具体步骤的规范。
有这么一句话:
里氏代换原则是继承复用的一个基础。
检验你是否遵循了里氏代换原则的方法:
如果调用的是父类的话,那么换成子类也完全可以运行。
动物 dongwu=new猫();其中【把猫换成狗】也是正常的就说明你是遵循这个原则的。
{注:
我在网上看过一个“企鹅是鸟不会飞”的例子,这也是自己犯这个错误的原因。
这例子在这不说了,你可以试着去找一下去。
}
5.接口隔离原则InterfaceSegregationPrinciple(ISP)
从字面上来讲就是一个不要把接口写的太臃肿。
查资料大致说的就是有两种分离方式一种是“定制服务”和“角色隔离”。
在工作当中有没有这样的问题存在:
同一个模块,因为没有安排得当两个人都去开发,最后一定是有个人白做了。
所以有时候,项目管理软件就显的那么的有必要。
定制服务:
大致来讲就是我针对一个客户端,我的一些方法放到一个接口里,另一个客户端我的一个类放在另一个接口里面。
角色隔离:
是指一个客户端有多个方法,多个方法写多个接口。
【友情提醒:
接口也不要分的太细,要不然结果就是接口太多。
】
6.迪米特原则LawofDemeter 又称LeastKnowledgePrinciple(LKP)最少知识原则
【我的理解就是:
这个原则不希望类与类之间不要建立直接联系。
】简单来说就是不和陌生人说话。
类与类之间一定会存在互相调用的?
网上查了一下,说可以用友元类来转达。
降低类本身和成员的访问权限,达到【低耦合,高内聚】是其目的。
【和ISP接口隔离原则一样,限制类与类之间的通信。
ISP限制的是宽度,而LoD迪米特原则限制的是通信的广度和深度。
】。
外观模式(FacadePattern)和中介者模式(MediatorPattern)就使用了迪米特法则。
一.设计模式
【创建型的设计模式】
1.单例模式
原则:
确保一个类只有一个实例,并提供一个全局访问点
举例:
打印机就是最好的例子,打印就是纸打印一个对象多的话就进行排队。
主要解决:
一个全局使用的类频繁地创建与销毁。
优点:
1、在内存里只有一个实例,减少了内存的开销,尤其是频繁的创建和销毁实例(比如管理学院首页页面缓存)。
2、避免对资源的多重占用(比如写文件操作)。
缺点:
没有接口,不能继承,与单一职责原则冲突,一个类应该只关心内部逻辑,而不关心外面怎么样来实例化。
//懒汉模式publicclassSingletonClass{
privatestaticSingletonClassinstance=null;
publicstatic synchronized SingletonClassgetInstance()
{
if(instance==null
{
instance=newSingletonClass();
}
returninstance;
}
privateSingletonClass(){
}
}//饿汉式//对第一行static的一些解释//允许我们在一个类里面定义静态类。
比如内部类(nestedclass)。
//把nestedclass封闭起来的类叫外部类。
//我们不能用static修饰顶级类(toplevelclass)。
//只有内部类可以为static。
publicclassSingleton{
//在自己内部定义自己的一个实例,只供内部调用
privatestaticfinalSingletoninstance=newSingleton();
privateSingleton(){
//dosomething}
//这里提供了一个供外部访问本class的静态方法,可以直接访问
publicstaticSingletongetInstance(){
returninstance;
}
}//双重锁的形式。
publicclassSingleton{
privatestaticSingletoninstance=null;
privateSingleton(){
//dosomething}
publicstaticSingletongetInstance(){
if(instance==null){
synchronized(Singleton.class){
if(null==instance){
instance=newSingleton();
}
}
}
returninstance;
}
}
1.简单工厂模式
原则:
封装改变,既然要封装改变,自然也就要找到改变的代码,然后把改变的代码用类来封装和降低对象之间的耦合度
举例:
夏天到了,去撸串的季节到了。
老板来10个板筋,5个腰子,20个串,10个鸡胗。
。
。
。
一会老板就给你上来了。
这就是工厂模式。
老板烤串就是工厂,你和你的兄弟们就是顾客。
只需要照着单子点即可,不需要知道老板具体是怎么做的。
主要解决:
主要解决接口选择的问题。
优点:
1、一个调用者想创建一个对象,只要知道其名称就可以了。
2、扩展性高,如果想增加一个产品,只要扩展一个工厂类就可以。
3、屏蔽产品的具体实现,调用者只关心产品的接口。
缺点:
每次增加一个产品时,都需要增加一个具体类和对象实现工厂,使得系统中类的个数成倍增加,在一定程度上增加了系统的复杂度,同时也增加了系统具体类的依赖。
这并不是什么好事。
///
///单位信息工厂模式
///
publicclassunit_factory
{
publicstaticunitcreate_unit_factory(stringunitname)
{
unitunit=null;
switch(unitname)
{
case"room":
{
unit=newunti_rooms();
break;
}
case"floor":
{
unit=newunti_floor();
break;
}
case"building":
{
unit=newunti_building();
break;
}
case"area":
{
unit=newunti_areas();
break;
}
}
returnunit;
}
}
///
///单位信息基类
///
publicclassunit:
wx_sbs_redis
{
publicfee_power_queryfee_power_query;
publicvirtualresultget_info()
{
resultret=null;
returnret;
}
}
///
///楼称派生类
///
classunti_floor:
unit
{
stringsign=fee_power_query.orgid+"|"+fee_power_query.uid+"|"+fee_power_query.area_id+"|"+fee_power_query.building_id+"|"+fee_power_query.cardno+"|"+fee_power_query.code;
if(!
fee_power_query.valid_floors())
returnResult((int)errcode.Interval,fee_power_query.msg);
Listlist=newList();
varrecents=newfee_recents().pick("fee"+fee_power_query.uid,"power_floor");
varret=newwxwebapi().invoke(i=>i.floors,gatapower);
returnret;
}
}
///
///房间派生类
///
classunti_rooms:
unit
{
}
///
///楼派生类
///
classunti_building:
unit
{
}
///
///校区派生类
///
classunti_areas:
unit
{
}
1.工厂模式
原则:
一个用于创建对象的接口,让子类决定实例化哪一个类,工厂方法使一个类的实例化延迟到其子类。
他强调的是单个对象的变化。
【工厂模式是我们最常用的实例化对象模式了,是用工厂方法代替new操作的一种模式】
举例:
2.抽象工厂模式
上面说到工厂模式,有一个问题,就是实现的调用要依赖于工厂类,如果扩展程序要修改工厂类,那么这样就违背了开闭原则。
为此用到了抽象工厂模式。
其实说道设计原则,抽象工厂模式更能体现的是里氏代换原则。
主要解决:
主要解决接口选择的问题。
原则:
为创建一组相关或相互依赖的对象提供一个接口,而且无需指定他们的具体类。
强调的是系列对象的变化。
优点:
当一个产品族中的多个对象被设计成一起工作时,它能保证客户端始终只使用同一个产品族中的对象。
缺点:
产品族扩展非常困难,要增加一个系列的某一产品,既要在抽象的Creator里加代码,又要在具体的里面加代码。
///
///抽象工厂类,提供创建两个不同地方的鸭架和鸭脖的接口
///
publicabstractclassAbstractFactory
{
//抽象工厂提供创建一系列产品的接口,这里作为例子,只给出了绝味中鸭脖和鸭架的创建接口
publicabstractYaBoCreateYaBo();
publicabstractYaJiaCreateYaJia();
}
///
///南昌绝味工厂负责制作南昌的鸭脖和鸭架
///
publicclassNanChangFactory:
AbstractFactory
{
//制作南昌鸭脖
publicoverrideYaBoCreateYaBo()
{
returnnewNanChangYaBo();
}
//制作南昌鸭架
publicoverrideYaJiaCreateYaJia()
{
returnnewNanChangYaJia();
}
}
///
///上海绝味工厂负责制作上海的鸭脖和鸭架
///
publicclassShangHaiFactory:
AbstractFactory
{
//制作上海鸭脖
publicoverrideYaBoCreateYaBo()
{
returnnewShangHaiYaBo();
}
//制作上海鸭架
publicoverrideYaJiaCreateYaJia()
{
returnnewShangHaiYaJia();
}
}
///
///鸭脖抽象类,供每个地方的鸭脖类继承
///
publicabstractclassYaBo
{
///
///打印方法,用于输出信息
///
publicabstractstringPrint();
}
///
///鸭架抽象类,供每个地方的鸭架类继承
///
publicabstractclassYaJia
{
///
///打印方法,用于输出信息
///
publicabstractstringPrint();
}
///
///南昌的鸭脖类,因为江西人喜欢吃辣的,所以南昌的鸭脖稍微会比上海做的辣
///
publicclassNanChangYaBo:
YaBo
{
publicoverridestringPrint()
{
return"南昌的鸭脖";
}
}
///
///上海的鸭脖没有南昌的鸭脖做的辣
///
publicclassShangHaiYaBo:
YaBo
{
publicoverridestringPrint()
{
return"上海的鸭脖";
}
}
///
///南昌的鸭架
///
publicclassNanChangYaJia:
YaJia
{
publicoverridestringPrint()
{
return"南昌的鸭架子";
}
}
///
///上海的鸭架
///
publicclassShangHaiYaJia:
YaJia
{
publicoverridestringPrint()
{
return"上海的鸭架子";
}
}
///
///如果绝味又想开一家湖南的分店时,因为湖南喜欢吃麻的
///所以这是有需要有一家湖南的工厂专门制作
///
publicclassHuNanFactory:
AbstractFactory
{
//制作湖南鸭脖
publicoverrideYaBoCreateYaBo()
{
returnnewHuNanYaBo();
}
//制作湖南鸭架
publicoverrideYaJiaCreateYaJia()
{
returnnewHuNanYajia();
}
}
///
///湖南的鸭脖
///
publicclassHuNanYaBo:
YaBo
{
publicoverridestringPrint()
{
return"湖南的鸭脖";
}
}
///
///湖南的鸭架
///
publicclassHuNanYajia:
YaJia
{
publicoverridestringPrint()
{
return"湖南的鸭架子";
}
}
1. 建筑者模式
原则:
将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。
举例:
网上很多都用组装电脑来阐述建造者模式,一个电脑都有cpu,内存条,主板,硬盘。
。
。
。
这些部件显然在创建的时候也是一个复杂的过程,但是如果我们如果要组装一台电脑是不需要知道这个过程的。
只需要把兼容部件拿过来组装即可。
把部件和是否兼容分离就需要用到建筑者模式。
优点:
1、建造者独立,易扩展。
2、便于控制细节风险。
缺点:
1、产品必须有共同点,范围有限制。
2、如内部变化复杂,会有很多的建造类。
publicclassDirector
{
publicvoidConstruct(IBuilderbuilder)
{
builder.BuildPartA();
builder.BuildPartB();
}
}
publicinterfaceIBuilder
{
voidBuildPartA();
voidBuildPartB();
ProductGetResult();
}
publicclassConcreteBuilder1:
IBuilder
{
privateProductproduct=newProduct();
publicvoidBuildPartA()
{
product.Add("部件A");
}
publicvoidBuildPartB()
{
product.Add("部件B");
}
publicProductGetResult()
{
returnproduct;
}
}
publicclassConcreteBuilder2:
IBuilder
{
privateProductproduct=newProduct();
publicvoidBuildPartA()
{
product.Add("部件X");
}
publicvoidBuildPartB()
{
product.Add("部件Y");
}
publicProductGetResult()
{
returnproduct;
}
}
publicclassProduct
{
IListparts=newList();
publicvoidAdd(stringpart)
{
parts.Add(part);
}
publicstringShow()
{
stringstr=string.Empty;
foreach(stringpartinparts)
{
str=str+part;
}
returnstr;
}
}
1.原型模式
原则:
用原型实例指定创建对象的种类,并通过拷贝这些原型创建新的对象。
举例:
西游记咱们应该都看过,悟空一根毫毛能变成千千万万的孙猴子,这就和这原型模式一样。
通过一个原型得到多个和原型一模一样的新对象。
主要解决:
在运行期建立和删除原型。
优点:
1、性能提高。
2、逃避构造函数的约束。
缺点:
1、配备克隆方法需要对类的功能进行通盘考虑,这对于全新的类不是很难,但对于已有的类不一定很容易,特别当一个类引用不支持串行化的间接对象,或者引用含有循环结构的时候。
2、必须实现Cloneable接口。
3、逃避构造函数的约束。
namespacePrototype
{
///
///ICloneable接口充当了抽象原型类的角色
///具体原型类通常作为实现该接口的子类
///
publicclassPrototypeICloneable_Resume:
ICloneable
{
privatestringname;
privatestringsex;
privatestringage;
privateWorkExperiencework;
publicPrototypeICloneable_Resume(stringname)
{
this.name=name;
work=newWorkExperience();
}
privatePrototypeICloneable_Resume(WorkExperiencework)
{
this.work=(WorkExperience)work.Clone();
}
//设置个人信息
publicvoidSetPersonalInfo(stringsex,stringage)
{
this.se