设计模式

链接:https://pan.baidu.com/s/1HxO2FwhF_SI5mp7eCCScdw?pwd=6666 
提取码:6666

模式概述

创建型模式:

结构型模式:将类或对象按某种布局组成更大的结构

行为型模式:描述类或对象之间怎样互相协作共同完成单个对象无法完成的任务

 

类与类之间的关系

关联关系:对象之间的引用。

 

一般关联:单向关联/双向关联/字关联

 

聚合关系

组合关系

依赖关系

继承关系

实现关系

软件设计原则

开闭原则

里氏代换原则

例如:a继承与A,某个方法依赖A,那么他也可以依赖a。但使用时要注意场合,因为这可能出现问题。

依赖倒转原则

例如:GameEntry要调Managers的onUpdate方法,但GameEntry不是直接调某一个Manager的onUpdate,而是让它实现带有onUpdate方法的接口,然后依赖接口。

接口隔离原则

例如:门有防水防火防盗功能,接口肯定是三个接口各实现一个功能,而不是都写在一个接口里。

迪米特法则

例如:就是找中介

合成复用原则

例如,使用继承复用就会在想新建一个类的时候,需要添加三个类

而此时用聚合复用就仅需加一个类

这只是一种情况,在其他情况下可能就是继承复用要更好。

 

设计模式

创建者模式

主要关注的点是“怎样创建对象?”,主要特地是“将对象的创建和使用分离”;

这样可以减低系统的耦合度,使用者不需要关注对象的创建细节;

单例模式

提供了一种创建对象的最佳方法;

涉及到一个单一的类,该类负责创建自己的对象,同时确保只有单个对象被创建;

这个类提供的一种访问其唯一对象的方式;

可以直接访问,不需要实例化该类的对象;

单例模式的实现

饿汉:因为在类加载时就创建了,如果后续一直不用他,就会占用内存。

懒汉:多线程情况下,当两个线程都进入了判断,就会出错。

改进:

 

工厂方法模式

简单工厂模式

:不是一种设计模式,反而像一种编程习惯

 

类构成:运行类Client,管理类CoffeeStore,简单工厂类:SimpleFactory,咖啡父类Coffee,子类AB

运行类去调管理类,管理类去找工厂创建,然后一路把对象返回到运行类。

但是也有缺点:

工厂模式

简单工厂模式是传字符串,然后工厂判断字符串,然后返回相应的类,这就有一个缺点,要增加类的时候就要修改判断字符串那块代码,因此违反了开闭原则;

 

而工厂模式就是传一个类,这个类实现的工厂的接口:

然后商店里就是直接去实现这个接口的方法;

 

抽象工厂模式

一个接口,负责创建:衣服、裤子、鞋子。

若干个工厂,如阿迪工厂,安踏工厂,实现这个接口。

阿迪工厂负责new阿迪衣裤鞋。

安踏工厂负责new安踏衣裤鞋。

这就是抽象工厂,阿迪生成的东西都是同一个产品族的;

安踏的鞋子和阿迪的鞋子是同一产品等级。

原型模式

用一个已经创建的实例作为原型,通过赋值该原型对象来创建一个和原型对象相同的新对象

结构:

遇到需要一个独立的类,这个类已经存在一个实例,类需要赋值的参数很多,但和已存在实例差不多时,可以使用克隆。

 

实现一般接口可以实现浅克隆,值类型都是独立存在的,引用类型还是引用的同一个地址上存储的数据;

因此可以是深克隆,不同语言有不同的方式,一般是使用序列化。

建造者模式

将一个复杂对象的构造与表示分离,使得同样的构建过程可以创建不同的表示

我们要去建造一个对象,该对象中有一堆参数需要赋值/运算;

这个时候,我们可以针对该对象建一个抽象类,其中的抽象方法就是针对需要建造的对象其中的某些参数;

然后具体类继承抽象方法     ---------------------->     实现抽象方法

当然,还需要一个设计师;(也可以不用,直接找工厂)

我们告诉设计师我们需要什么样的对象,设计师去找具体的Builder去建造

优缺点

其二,在创建某个对象时,该对象初始化需要很多很多很多参数去初始化;

这个时候,我们可以套一层建造者模式,该建造者对象就是该对象的一部分;Build↓

然后我们let phone = Phone.Builder();时就会得到一个Build对象;

用该Build对象去点方法,就可以进行赋值,最后再Build对象的build()方法,就可以得到目标对象。

某些差别

简单来说就是工厂模式创建整个对象,而且可以批量;

但建造者模式就是针对单个对象的详细创建;

结构型模式

该模式就是描述如何将类和对象按某种布局组成更大的结构;

类结构一般采用 继承机制来组织接口和类;

对象结构一般采用 组合聚合来组合对象;

由于组合聚合比继承的耦合性更低,所以对象结构比类结构具有更大的灵活性。

代理模式

抽象类:

真实类:

代理类:

因此,代理类可以实现大量的接口,供客户端去调用

适配器模式

类适配器

此时,Computer类只能去读SD卡(规范的接口):

然后我们有一个杂乱无章的,需要Computer去读的类(适配者类):

这个时候就需要适配器类:(继承适配者类,实现规范接口):

此时,就可以在实现接口的类里面把适配者变得有规律;

从而让Computer类去实现。

对象适配器

但这样就违背了组合复用原则

因此,轮到对象适配器出手了,这样,一个适配器也可以把多个适配者规范化;

 

类适配器就是继承嘛,很难再修改,

对象适配器就是把继承变成了组合聚合,这样就大大降低了耦合性

 

在适配器类里面存各种各样需要适配的类:

给每个类准备一个赋值方法,同时把标记打上:

然后就可以调用规范化方法:

此时,调用者就会得到适配成目标接口的方法,如果目标不是接口,是类;

(看调用者需要什么,需要类就去继承类,需要接口就去实现接口;

此时这里是Computer类需要ISDCard接口)

那也可以把实现接口换成继承目标类,然后重写目标所需的类就行了。

装扮者模式

当前写法:

我有一份快餐,底下有炒面/炒饭,因此衍生出了快餐-炒面类/快餐-炒饭类,

然后再底下,有加培根/加鸡蛋/加火腿,因此衍生出了

快餐-炒面类-鸡蛋/培根/火腿/鸡蛋培根/鸡蛋火腿.............

类爆炸了。

因此,我有一个装扮者模式

案例:

此时,炒饭炒面继承于快餐类,但就是价格不一样,其他的功能都是一样的;

但但此时需要对炒饭炒面类进行大量的扩展,这个扩展的类的父类可以继承快餐类,也可以继承其他类,但这个类中肯定聚合了一个快餐类;

然后这个Garnish类,装饰者类,会有针对炒饭炒面类的方法;

 

直接看main:

Out:

第一个炒面,就是new,然后会在构造函数里赋值

调重写的抽象方法打印出来就是炒面12

 

然后第二个,new了一个继承Garnish的鸡蛋,传了一个炒面进去;

构造函数里把fastFood存了起来,然后为自己的price和desc赋值了

此时去调下边的两个方法,就是:

d鸡蛋+d炒面;(“鸡蛋”+“炒面”=“鸡蛋炒面”)

p鸡蛋+p炒面;(1+12=13)

此时main方法里面的fastFood就是一个Garnish对象

 

然后第三个:还是new了一个鸡蛋,传了一个Garnish对象进去

此时去调下边的两个方法,就是:

d鸡蛋+F.getDesc()(d鸡蛋+d炒面);

(“鸡蛋”+(“鸡蛋”+“炒面”)=“鸡蛋鸡蛋炒面”)

p鸡蛋+F.const()(p鸡蛋+p炒面);(1+(1+12=13)=14)

 

然后第四个:new了一个培根,传了一个Garnish对象进去

此时去调下边的两个方法,就是:

d培根+F.getDesc()(d鸡蛋+F.getDesc()(d鸡蛋+d炒面));

培根+(“鸡蛋”+(“鸡蛋”+“炒面”))=“培根鸡蛋鸡蛋炒面”

p培根+(p鸡蛋+F.const()(p鸡蛋+p炒面));2+(1+(1+12))=16

 

最后第五个:new了一个培根,传了一个Garnish对象进去

此时去调下边的两个方法,就是:

d培根+F.getDesc()(d培根+F.getDesc()(d鸡蛋+F.getDesc()(d鸡蛋+d炒面)));

“培根”(“培根”+(“鸡蛋”+(“鸡蛋”+“炒面”)))=“培根培根鸡蛋鸡蛋炒面”

p培根+(p培根+(p鸡蛋+F.const()(p鸡蛋+p炒面)));2+(2+(1+(1+12)))=18

 

感觉和递归类似

 

Tips

代理和装饰者模式的区别

桥接模式

使用场景和定义

案例

将继承变成聚合,在操作系统里聚合一个文件接口就可以了。

操作系统父类,里面有桥(构造函数传参)-接到视频文件接口(由内部变量存起来)

子类继承,实现父类方法:

被桥接的对象(实现化角色)

Tips

外观模式

定义

例子

其实无时无刻不在用,封装好一堆类,向外提供一个方法,调用此方法会进行一堆操作

Tips

 

组合模式

Tips

是一种管理树形结构的结构型模式,由一个抽象类管理,该抽象类是针对叶子和根而写的,所以只是一些公共的方法,属性;

像根节点上面就会有存储枝的属性,而叶子没有;

然后抽象类实现全部方法,叫做透明组合模式;

由根和叶子单独实现方法,叫做安全组合模式。

享元模式

定义

结构

此时就是内部模式;

此时就是外部模式;

子类就是这种:

然后有个工厂,用了单例饿汉式

然后客户端就这样去调用:

享的同一个元,因此下次使用的,可能是上次修改过的。需要注意

优缺点/使用场景

为什么有外部内部?

因为指向的对象是同一个,你在创建修改使用对象过后,下次在拿出来时,它的初始状态就是你上次用完时的状态。

外部化:就是享元目标有一个属性,你在类中写一个公开的方法供客户调用/修改。

内部化:希望该属性是上次使用完之后的。

 

C#的string是享元,Java的-128到127的int是享元

 

行为型模式

行为型模式用于描述程序在运行时复杂的流程控制

即描述多个类或对象之间怎样互相协作共同完成单个对象无法完成的任务

他涉及算法与对象间责任的分配

 

行为型模式分为类行为模式和对象行为模式

前者采用继承机制 在类间分配行为,后者采用组合聚合 在对象键分配行为

由于组合聚合关系比继承关系耦合度低,满足“合成复用原则”

所以对象行为比类行为具有更大的灵活性

 

模板方法 和 解释器 是 类行为,其他为对象行为

模板方法模式

概述

结构

案例

做菜:倒油->热油->放菜->放调料->翻炒.

其中,倒油热油翻炒是确定的行为,但放菜和放调料不知道是什么

因此我们可以这样做,先确定行为顺序:(模板方法)

然后把确定的行为写好:(基本方法-具体方法)

然后写不确定抽象行为:(基本方法-抽象方法)

然后由子类去实现:(具体子类)

然后调用之后就会去实现子类的方法

优缺点

适用场景

策略模式

定义

该模式定义类一系列算法,并将每个算法封装起来,是他们可以相互替代且算法的变化不会影响使用算法的客户。

策略模式属于对象行为模式,他通过对算法进行封装,把使用算法的责任和算法的实现分割开来,并委派给不同的对象对这些算法进行管理。

结构

案例

其实就是简单的调用实现接口的方法,接口方法:

子类实现:

然后来一个环境类去调接口的具体方法:

优缺点

使用场景

命令模式

定义

将请求封装为一个对象,使发出请求的责任和执行请求的责任分割开。

两者之间通过命令对象进行沟通,这样方便将命令对象进行存储、传递、调用、增加、管理

结构

案例

从客户端讲起:

顾客来点单,点了两个单

命令类:(就是存了桌号和菜品<菜名,几份>)

然后new了一个执行者

执行者:

然后new了命令,并传了参

抽象命令类和具体命令类    就一个调用()

New的时候存了单条命令和执行者

Execute的时候就是把所有命令都遍历一遍,然后让执行者拿数据执行;

但这个execute是调用者(waitor)去调用

把命令全部收集起来

这么做的目的就是为了把调用者和执行者解耦;

运行时:就是调用者遍历他接收到的命令,然后执行命令

命令执行时会根据它被创建时永远的参数,拿着这些参数去执行方法

其中一个参数就是执行者,把其他参数传给执行者,让执行者拿着这些参数去执行方法

 

优缺点

使用场景

责任链模式

定义

张三请假50天,找 A 去批准,A看看自己能不能批50天的假,发现最多批7天(悲);

然后 A 把张三的50天请求往 B 上发,B可以批30天的;

然后 B 把张三的50天请求往 C 上发,C给批了;

结构

案例

请求类:一条请求,由名字,请假天数,原因组成,new的时候要初始化所以参数

 

抽象处理者类:初始化时传入自己的职责范围(可以处理start到end天数的请求)

设置下一个职责更高的对象

该领导拿到请求的处理方法(抽象方法):

对外提供一个提交请求的方法:

具体处理者:01可以处理0-1天的,02处理1-3天的,03处理3-7天的;

客户创建请假条,交给自己的上级 01 去处理。

Out:

优缺点

状态模式

写个状态机

因此我们用到状态模式

定义

对有状态的对象,把复杂的“判断逻辑”提取到不同的状态对象中,允许状态对象在其内部状态发生改变时,改变其行为

结构

案例

和上图差不多,就是在创建电梯对象的时候,把所有状态都new了一个

然后有一个参数去存当前状态,想修改状态时就会直接去调当前状态里的方法,

感觉就是把参数变成了类

 

抽象类,之所以要存这个Context也是为了拿到其中的当前状态,然后修改

优缺点及使用场景

观察者模式

定义

它定义了一种一对多的依赖关系,让多个观察者对象同时监听某一主体对象。

这个主体对象在状态变化时,会通知所有的观察者对象,时他们能够自动更新自己。

结构

案例

 

公众号是主体对象,用户是观察者

 

客户端:

主体里有这些方法:加对象,删对象,给对象们发消息

由于发消息时,发送的对象可能有很多种,所以只需要他们实现该接口就可以了

某一对象

优缺点及使用场景

中介者模式

使用场景及定义

定义一个中介对象来封装一系列对象之间的交互,使原有对象之间的耦合松散,且可以独立地改变他们之间的交互

结构

案例

抽象中介者,对外提供一个方法

具体中介者,聚合所有需要通信的对象,并提供对象需要的方法

抽象同事类,存了同事类都需要的东西,当然也需要中介者

租房者调constact函数->传信息和自身给中介者->中介者拿到消息去判断对象,然后转发给另一个对象->房主收到信息,输出

优缺点

使用场景

 

迭代器模式

定义

提供一个对象顺序访问聚合对象中的一系列数据,而不暴露聚合对象的内部表示

结构

案例

就是C#的foreach

需要遍历的对象:Student  

抽象迭代器接口:泛型的  

实现该接口:            

由客户去遍历:new数组,new迭代器,给数组加对象

然后就是循环遍历

然后就是,不止数组,只要是实现的该接口的对象,都能够遍历,可以是树,可以是其他的

只要你在next加上你的下一个对象是什么就行。

优缺点及使用场景

访问者模式

定义

在某些数据结构中,会有各种各样的元素,全写在一起的话会很复杂,因此需要一个访问者去封装:处理这些元素的操作。

当然,是在不改变数据结构的前提下进行的新操作。

结构

案例

抽象访问者: 人,去访问对象结构里面的数据,动物

具体访问者:主人,给个动物,去喂动物

抽象元素角色:对象结构中的数据,向外提供一个可访问的接口

具体元素角色:具体实现

结构对象:动物数据,和把该数据交给访问者管理的方法;

优缺点

使用场景

 

备忘录模式

定义:撤销是怎么实现的

结构

案例

“白箱”:对所以对都提供一个宽接口,即所有存储的状态对所有对象公开:

角色:战斗开始初始化,存档,战斗时血掉光,然后读档

 

这个就是一个存档:

存档管理者:

这就是一个完整的备忘录模式(白箱)

之所以叫白箱,所是因为此时,管理者可以读取并修改存档。

 

因此需要,黑箱:

简单理解了一下,管理者存的是接口,而接口里没有任何东西

而角色对象里面存的是子类,子类里有一切东西。

就不截图了

简单来说,就是在GameRole中存了一个,继承Memento接口的类,然后是私有的,

然后把这个类存到管理者类里面时,是以接口的方式存的,因此管理者拿不到

但玩家去读档的时候,拿到的也是接口类,因此需要强转(因为知道强转的目标类)

优缺点及使用场景

 

解释器模式

概述

要做一个加减计算器,可能需要提供add(int p1, int p2)这样的方法;

或者三个参数四个参数或者数组,但

定义

给定一个语言,定义它的语法表示,并给出一个解释器,这个解释器使用该语法定义来解释语言中的句子。

结构

说实话有点难理解,感觉他这个例子不好

首先是Context里,map里面(其实就是存了一堆数据,去存和拿,没其他东西了)

然后,就根据这些数据去创建一棵树

 

当然,我们需要对这棵树进行定义,即,解释器

 

抽象表达式类,提供解释方法interpret

其中一种定义:加法,需要参数,解释时,就是把l和r的解释结果相加

减法也类似,就是把加法类里面的+号全换成了-号了

调用时,就是去创建一棵树

 

ABCD是Variable对象,解释的时候就直接拿到对象了

然后去解释该expression。。。。等于4

优缺点

使用场景

posted @ 2023-12-29 10:15  被迫吃冰淇淋的小学生  阅读(15)  评论(0)    收藏  举报