装饰器模式
官方定义: 动态地给⼀个对象增加⼀些额外的职责。就增加功能而言,装饰器模式比生成子类更为灵活。 —— 《设计模式》GoF
通俗解释: 装饰器是为了给对象增加额外职责而产生的, 有点粉刷的意思, 房子已经存在了, 在房子的表面加上一层粉刷. (而且它的优势是相较于继承而言的, 相比直接继承, 装饰器更加灵活, 耦合度更低)
应对与 ”过度的采取类继承扩展对象的功能“ 的情况
继承为类型引入的静态特质,使得这种扩展方式缺乏灵活性;并且随着子类的增多(扩展功能的增多),各种子类的组合(扩展功能的组合)会导致子类数量的膨胀。
(继承下来就是实实在在的一份负担, 代码的膨胀, 类的膨胀.) 但是很多时候其实我们没有必要去继承, 完全可以使用组合的方式来根据需求动态的实现对象功能的扩展, 以解决子类数量膨胀的问题. 使得功能扩展所带来的影响,代价最小,没必要说来一个新的功能扩展就新创建一个类。
这个类图其实很奇怪, 我刚看见的时候就在想,为啥又是继承, 又是组合的, 继承是为了复用之前的框架, 接口, 裸机 你只有有了之前的房子,才能粉刷装饰吧, 继承体现的是最初的裸机, 接口, 组合完成动态的修饰, 装饰。
这个组合还是组合抽象类本身,绝对看的让人很迷,组合的虽然是抽象类本身, 但是抽象类是一个接口,它可以代表它的一切派生类, 这样便使得这个组合对象可扩展性很强.
模式要点:
- 通过采用组合而非继承的手法,Decorator模式实现了在运行时动态扩展对象功能的能力,而且可以根据需要扩展多个功能。避免了使用继承带来的“灵活性差”和“多子类衍生问题”。
- Decorator类在接口上表现为is-a Component的继承关系,即Decorator类继承了Component类所具有的接口。但在实现上又表现为has-a Component的组合关系,即Decorator类又使用了另外一个Component类。
- Decorator模式的目的并非解决“多子类衍生的多继承”问题,Decorator模式应用的要点在于解决“主体类在多个方向上的扩展功能”——是为“装饰”的含义。
记忆技巧: 继承复用接口,组合复用实现细节,动态组合
代码场景: 工资计算, 基本员工的工资是天数*100, 经理员工是基本工资 + 加成add. 老板更是在经理员工的基础上增加10倍加成
实现代码如下:
如下是大佬写的一份代码: 大家也可以赏析一下:
相关视频推荐
学习地址:
需要C/C++ Linux服务器架构师学习资料加qun获取(资料包括C/C++,Linux,golang技术,Nginx,ZeroMQ,MySQL,Redis,fastdfs,MongoDB,ZK,流媒体,CDN,P2P,K8S,Docker,TCP/IP,协程,DPDK,ffmpeg等),免费分享
工厂方法模式
官方定义: 定义一个用于创建对象的接口,让子类决定实例化哪一个类。Factory Method使得一个类的实例化延迟(目的:解耦,手段:虚函数)到子类。——《设计模式》GoF
通俗解释:简单来说就是在工厂基类中定义一个抽象接口, 将整个接口的实例化延迟到一个具体的子类工厂(具体工厂),解耦合. ---- 之后对于工厂的依赖都是依赖稳定的工厂基类
这个类图感觉不算特别完善, 最好可以在Factory下面在继承具体的Factory感觉比较好.
实现代码如下:
要点:
- Factory Method模式用于隔离类对象的使用者和具体类型之间的耦合关系。面对一个经常变化的具体类型,紧耦合关系(new)会导致软件的脆弱。
- Factory Method模式通过面向对象的手法,将所要创建的具体对象工作延迟到子类,从而实现一种扩展(而非更改)的策略,较好地解决了这种紧耦合关系。
- Factory Method模式解决“单个对象”的需求变化。缺点在于要求创建方法/参数相同。
使用场景:
解决创建过程比较复杂,希望对外隐藏这些细节;
- 比如连接池,线程池;
- 隐藏对象真实类型;
- 对象创建会有很多参数来决定如何创建;
- 创建对象有复杂的依赖关系;
本质记忆技巧: 延迟到子类进行创建实现
抽象工厂模式
提供一个接口,让该接口负责创建一系列“相关或者相互依赖的对象”,无需指定它们具体的类。——《设计模式》GoF
通俗解释:本质上来讲, 无论是抽象工厂模式, 还是简工厂方法模式,均是属于对象创建模式. 抽象工厂模式相对于工厂方法而言核心差别在于它是负责相关联的一系列的产品, 对象的创建. 不再是单个产品的创建, 而是系列产品的创建, 两者差别仅此而已.
一个抽象工厂下面的两个具体工厂生产的两种产品是搭配产品。好比如说:瓶身与瓶盖两个产品的加工厂. 产品相互依赖,配套. 可以进行扩展, 比如说瓶子也有种类,矿泉水瓶,可口可乐瓶子,芬达瓶子等等. 这个瓶身瓶盖一定是配套生产的. (对应一系列相关,相互依赖的对象)
记忆技巧: 配套产品生产
适配器模式
定义: 将一个类的接口转换为用户需要的另一个接口。Adapter使得原本由于接口不兼容不能在一起工作的那些类可以一起工作。 ——《设计模式》GoF
通俗解释:简单来说就是适配接口, 本来一个类的接口是和用户需要的接口不统一的, 但是现在需要使用这个类的一些功能, 于是可以抽象出来一个中间的适配器类, 进行组合这个需要使用的类对象,并且适配接口,进而实现接口不兼容的类功能, 接口也可以使用.
说到适配器模式,我还想说所有学习C++的大家,只要学了STL, 容器适配器学的还不错的,仿写过stack,queue两个容器适配器的实现的,你们都已经使用了适配器模式了. 只是当时还不知道自己用的是适配器模式. 想想好像确实就是适配新的接口.
push_back-----> push pop_back ----> pop 针对stack而言
场景引入, 简单实现一下适配器模式
要点总结:
- Adapter模式主要应用于 "希望复用一些现成类, 但是接口又与复用环境不一致的情况", 在遗留代码复用, 类库迁移方面非常有用
- 适配的方式使用的是对象组合的方式, 更加符合松耦合的设计原则
- 原来的接口是稳定的,新的外来的需求是变化的,那么可以通过继承原来的接口,让原来的接口继续保持稳定,在子类通过组合的方式来扩展功能。 继承原来的接口(用户需要使用的接口, 复用其他类对象的接口,子类中组合扩展)
记忆技巧: 继承使得接口转换匹配, 组合复用已有类功能
代理模式
官方定义:为其他对象提供⼀种代理以控制(隔离, 使用接口)对这对象的访问。
——《设计模式》GoF
通俗解释:代理完成职责,代理一个具体类完成职责(接口职责, 相同的接口), 常见的代理, 婚庆代理, 代理商.
代理层出现的原因,背景,优势.
在有些系统中,为了某些对象的纯粹性,只进行了功能相关封装(稳定点),后期添加了其他功能 需要对该对象进行额外操作(变化点),为了隔离变化点(也就是不直接在稳定点进行修改,这样 会让稳定点也变得不稳定),可以抽象一层代理层
首先解释一下纯粹性:纯粹性指的是接口中仅仅只是实现功能,而不需要进行权限判断,引用计数等等其他的额外操作
代理类是一个中介层, 并不做具体的业务细节实现。而是介于客户类和具体的委托代理类之间的中间层. 作用在于对委托代理类使用前后的一些处理扩展, 让真正的RealSubject类保持纯粹 真正的业务功能其实还是委托代理类实现的。代理类是做中间处理和扩展的. (对已有对象的额外操作, 放在代理层)
简单实现:
模式要点:
- 远程代理(隐藏⼀个对象存在不同的地址空间的事实),虚代理(延迟加载lazyload),保护代理(在代理前后做额外操作,权限管理,引用计数等)
- 在分布式系统中,actor模型(skynet)等常用的设计模式
本质:控制对象访问, 代理RealSubject, 处理对RealSubject访问前后的扩展需求. 权限验证, 引用计数等
设计模式的学习确实是有点虚无的. 特别是没啥工作经验的,学完之后根本不知道咋用到实际项目中实现重构项目的设计,持续重构形成自己的设计模式。 我们也没有经历过没有任何设计原则的Bad Smell Code的维护,所以体会是没有实践过的前辈们深入的
但是我觉得提早了解和具备遵循设计原则这样的大思想是我们需要具备的,不一定强行套入设计模式,可以先是我们的代码遵循设计原则。 遵循设计原则的代码往往更容易重构和维护
IT技术路漫长久远。