设计模式的个人学习总结

借用李建忠老师的话“设计模式的目的是,管理变化,提高复用”,所以学习完设计模式后,要避免在开发项目种 “为了使用设计模式而使用设计模式” 这种思想,当出现了下面几种情况时们就要避免使用设计模式

所有的设计模式其实都或多或少的依赖着八大原则

八大设计原则
1.依赖倒置原则:
高层模块不依赖底层模块,二者都应该依赖抽象,
抽象不依赖实现细节,实现细节应该依赖于抽象。
这一原则与下面的针对接口变成而不是针对实现编程是一个道理,我们设计一个程序,我们应该先想好我们想要抽象什么,它应该具有什么样的能力,而不是先考虑怎么实现,这其中的具体方法,而最后在根据自己写的具体实现,从而汇总出最后的接口是什么。
2 开放封闭原则:
对拓展开放,对更改封闭
类模块应该是可 拓展的,但是不可修改的。
我们应该定义好接口之后就尽可能保证接口层的稳定,
3 单一职责原则:
一个类应该仅有一个引起他变化的原因
变化的方向隐含类的责任
若一个类中变化的部分过多,从而加剧了程序的维护难度,从而也许会修改这个类中的接口部分,也就违反了上面的第二原则。
其中变化(使用的具体实现等等),其中一定要明确这个部分中的具体目的。
4 Liskov替换原则:
通俗点讲,就是只要父类能出现的地方,子类就可以出现,而且替换为子类也不会产生任何错误或异常。

里氏替换原则为良好的继承定义了一个规范,

1. 子类必须完全实现父类的方法。

2. 孩子类可以有自己的个性。

3. 覆盖或实现父类的方法时,输入参数可以被放大。

4. 覆盖或实现父类的方法时,输出结果可以被缩小。
5 接口隔离原则:
接口隔离原则就是客户端不应该依赖它不需要的接口,或者说类间的依赖关系应该建立在最小的接口上。
设计对象的时候我们应该明确的知道这个对象应该要包含什么功能,然后做出相应的接口,其余一些客户不用的方法全部隐藏起来。
6 优先使用对象组合,而不是类继承:
继承在某种程度上破坏了封装性,子类父类耦合度高
对象组合则只要求被组合的对象具有良好的定义的接口。

具体的实现可以理解为:A类中有指向B的基类的指针ptr,当构建A类对象的时候通过传入B的具体子类吗,然后使用ptr来调用B子类中的具体函数,这种就可称作A类对象和B类对象的组合。
7 封装变化点
使用封装来创建对象之间的分界层,
让设计者可以在变化的另一侧修改,而不会对另一侧产生不良影响,
从而达到层次间的松耦合。
8 针对接口编程,而不是针对实现编程
不将变量类型声明为某个特定类型的具体类,而是声明为某个接口。
客户程序无需知道对象的具体类型,只需要知道对象所具有的接口。
减少系统中各部分的依赖关系,从而实现”高内聚,松耦合“的类型设计方案。

我个人觉得李建忠老师的分类方法跟容易理解设计模式的之间的作用和区别,所以下文就是按 “封装变化”的角度对模式分类

1.组件协作:

Template Method(模板方法)

模板模式:定义一个操作中的算法的骨架,而将一些步骤延迟到子类中。模板方法使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。

当多个类有相同的方法,并且逻辑相同,只是细节上有差异时,可以考虑使用模板模式。具体的实现上可以将相同的核心算法设计为模板方法,具体的实现细节有子类实现。

将稳定的部分放到抽象类中,将变化的实现细节延时的子类中实现,这是模板模式最核心的思想

下图中红色圈代表稳定,蓝色圈代表着变化

Strategy Pattern(策略模式)

策略模式是指定义一系列的算法,并将每一个算法封装起来,而且使它们可以互相替换,使得算法可以独立于使用它的客户端而变化。也就是说这些算法所完成的功能类型是一样的,对外接口也是一样的,只是不同的策略使得环境角色表现出不同的行为。

策略模式使用的就是面向对象的继承和多态机制,从而实现同一行为在不同场景下具备不同实现。

策略模式本质:分离算法,选择实现

 

Observer Pattern(观察者模式)

观察者模式具体的阐述比较复杂,下面引用一段Wiki百科里对它的解释

The observer pattern is a software design pattern in which an object, called the subject, maintains a list of its dependents, called observers, and notifies them automatically of any state changes, usually by calling one of their methods.

 其实说白了观察者模式就是一种抽象的依赖通知机制,想要订阅的对象类中有一个存放着订阅者的容器,当被订阅的对象状态放生改变时,就可已通过遍历该容器,来通知所有的订阅者。

 单一职责:

Decorate Mode(装饰模式)

Attach(附上) additional(附加的) responsibilities to an object dynamically(动态地)keeping the same interface(接口). Decorators provide a flexible(灵活的)alternative to subclassing(子类化)for extending functionality.

 装饰模式是在不必改变原类文件和使用继承的情况下,动态地扩展一个对象的功能。它是通过创建一个包装对象,也就是装饰来包裹真实的对象。

既然可以动态增加功能,那么这功能也可以动态地被撤销
重点:扩展/增强 对象的功能 ,而非 限制 对象的功能

装饰模式要解决的问题:提供一种修改类的行为,而避免创建众多的派生类的途径。它是一种对象结构型模式,就增加功能来说,装饰模式比生成子类更为灵活。

 Bridge Pattern(桥接模式)

Decouple(解耦)an abstraction from its implementation(实现)so that the two(两者) can vary(变化)independently.

解耦抽象(业务功能)和实现(平台实现),使得两者可以独立的变化。

桥接模式即将抽象部分与它的实现部分分离开来,使他们都可以独立变化。

桥接模式将继承关系转化成关联关系,它降低了类与类之间的耦合度,减少了系统中类的数量,也减少了代码量。属于对象结构型模式。

桥接模式类似于多重继承方案,但是多重继承方案往往违背了类的单一职责原则,其复用性比较差。桥接模式是比多重继承更好的替代方案(即组合)。

C++设计模式——桥接模式(Bridge Pattern)_c++桥接模式例子-CSDN博客

 对象创建

Factory Pattern(工厂模式)

工厂方法模式将生成具体产品的任务分发给具体的产品工厂。在代码实现上,工厂方法模式在简单工厂模式的基础上增加对工厂的基类抽象,不同的产品创建采用不同的工厂创建(从工厂的抽象基类派生),这样创建不同的产品过程就由不同的工厂分工解决:

FactoryA专心负责生产ProductA,FactoryB专心负责生产ProductB,FactoryA和FactoryB之间没有关系;如果到了后期,如果需要生产ProductC时,我们则可以创建一个FactoryC工厂类,该类专心负责生产ProductC类产品。

该模式相对于简单工厂模式

优势:

便于后期产品种类的扩展。如果需要增加新的产品类,只需要扩展一个相应的工厂类即可。
缺点:

产品类数据较多时,需要实现大量的工厂类,这无疑增加了代码量

Abstract Factory(抽象工厂模式)

抽象工厂是一个产品簇的概念,一个工厂可以生产多种业务相关的产品。我们在工厂方法的基础上扩充一下代码:定义一个抽象工厂接口AbstractFactory,通过不同的方法生产出一个“抽象”产品簇(Phone和PC)。回过头来再看工厂方法,事实上它就是抽象工厂最简单的一种场景设计——只生成一种产品。

抽象工厂模式通过在AbstarctFactory中增加创建产品的接口,并在具体子工厂中实现新加产品的创建,当然前提是子工厂支持生产该产品。否则继承的这个接口可以什么也不干。

 Prototype Pattern(原型模式)

Specify the kinds of Objects to create using a prototypical instance, and create new objects by copying this prototype.

原型模式是一种创建型模式,允许一对象再创建另外一个可定制的对象,而无需知道任何创建的细节。

通过复制(克隆、拷贝)一个指定类型的对象来创建更多同类型的对象。这个指定的对象可被称为“原型”对象,也就是通过复制原型对象来得到更多同类型的对象。

原型模式很少单独出现,一般是和工厂方法模式一起出现,通过clone()方法创建一个对象,然后由工厂提供给调用者

 对象性能:

Singleton Pattern(单例模式)

单例模式顾名思义,保证一个类仅可以有一个实例化对象,并且提供一个可以访问它的全局接口。实现单例模式必须注意一下几点:

单例类只能由一个实例化对象。
单例类必须自己提供一个实例化对象。
单例类必须提供一个可以访问唯一实例化对象的接口。
其特点是只提供唯一一个类的实例,具有全局变量的特点,在任何位置都可以通过接口获取到那个唯一的实例;

单例模式又分为懒汉模式和饿汉模式,

饿汉模式:单例类定义的时候就进行实例化。在访问量比较大,或者可能访问的线程比较多时,采用饿汉实现,可以实现更好的性能。这是以空间换时间。

懒汉模式:故名思义,不到万不得已就不会去实例化类,也就是说在第一次用到类实例的时候才会去实例化一个对象。在访问量较小,甚至可能不会去访问的情况下,采用懒汉实现,这是以时间换空间。(有线程安全的问题,在c++11后,一般有静态局部对象方法创建懒汉模式)

Flyweight Pattern(享元模式)

Use sharing to support large numbers of fine-grained(细粒度的)objects efficiently.

 C++设计模式——享元模式(Flyweight Pattern)_c++ 享元模式-CSDN博客

简单的来说:当有大量的相似的类对象创建需求出现时(即如果A对象和B对象对于客户端的使用来说是完全一样的),我们就可以通过对象共享的方式来减少创建对象的数量,以减少内存占用和提高性能

接口隔离:

 Facade Pattern(门面模式)

Facade Pattern provides a unified(统一的)interface (接口)to a set of interfaces in subsystems(子系统). Facade defines a higher-level interface that makes the subsystem easier to use.

说人话就是:门面模式用来简化接口的。
通常,我们觉得一个子系统不好用,可能是因为它提供的外部接口太接近底层组件,让我们用起来感到很麻烦。因为我们不需要知道内部细节,我们只想要一个“一键完成”功能,调用子系统的某个方法,它可能替我们完成了图片预处理,而不是靠我们自己来调用灰度化方法、图像增强算法、噪声处理方法等等来一步步实现预处理。
如果子系统提供的接口太接近底层组件,不仅不易用,而且破坏了子系统的封装(想调用子系统就必须了解其各个底层组件,我们被迫知道了太多不应该知道的细节)

 Proxy Pattern(代理模式)

The proxy design pattern allows you to provide an interface(接口) to other objects by creating a wrapper(包装) class as the proxy. The wrapper class, which is the proxy, can add additional(附加的) functionality to the object of interest without changing the object’s code.

代理模式,就是封装一个代理中介类 ,来控制客户端对于某个对象的访问,有人可能会问“那为什么客户端不直接访问那个对象呢”,其实是因为客户端在访问对象时执行一些额外操作(例如,延迟加载、缓存、日志记录等),这时候就可已通过代理类来完成这些额外操作。

代理类主要负责为委托类预处理消息、过滤消息、把消息转发给委托类,以及事后对返回结果的处理等。代理类本身并不真正实现服务,而是通过调用委托类的相关方法,来提供特定的服务。真正的业务功能还是由委托类来实现,但是可以在业务功能执行的前后加入一些公共的服务。

智能指针的引用计数实现,应该就是采用代理模式实现的。个人看法。
————————————————

 原文链接:https://blog.csdn.net/leonardohaig/article/details/106594702

 

Adapter Pattern (适配器模式) 

Convert(转换)the interface(接口) of a class into another interface clients expect. Adapter lets classes work together that couldn’t otherwise(否则) because of incompatible(不相容) interfaces.

适配器模式的设计在于将某些功能与第三方需求接口适配对接,且避免第三方接口与功能代码过多耦合。

在设计初初,不要考虑使用此模式。仅在功能完善,需要实现第三方接口时,没必要迎合第三方的需求对原来的设计大动刀戈,可以尝试使用适配器模式。

多用于想应用某些功能,但是功能类的接口与需求的接口不兼容时,采用适配器模式来解决。主要应用在以下场景:

新旧接口兼容软件版本升级,部分旧接口还在被使用。需要保留旧的接口,增加新接口,使两者兼容。

第三方接口的适配在系统功能稳定的情况下,有第三方新的接口需求需要对接。

统一多个类相同功能的接口例如统一不同类型数据库的访问接口。

总的来说,适配器不是在详细设计时添加的,而是解决正在服役的项目的问题。 此,为区分对象适配器模式和策略模式的重要区别。

 状态变化:

State Pattern(状态模式)

Allow an object to change its behavior when its internal(内部的) state changes. So that the object appears to have modified(修改了) its behavior

状态模式,就是把所有的状态抽象成一个个具体的类,然后继承一个抽象状态类,在每一个状态类内封装对应状态的行为,符合开放封闭原则,当增加新的状态或减少状态时,只需修改关联的类即可。很适合多分支行为方法的处理,这里的多分支,当然是状态比较多的情况下,如果只有小于4个状态,个人认为还是分支处理简单些。

 数据结构:

Composite Pattern(组合模式)

Compose objects into tree structures to represent part-whole(部分-整体) hierarchies(层次结构).Composite lets clients treat individual objects and compositions(成分) of objects uniformly(均匀的).

组合模式之所以被分类在数据结构下,是因为这个模式的实现就是依赖着一种树型结构 ,

可以把一组相似的对象当作一个单一的对象。组合模式依据树形结构来组合对象,用来表示部分以及整体层次。这种类型的设计模式属于结构型模式,它创建了对象组的树形结构。

组合模式 一般用来描述整体与部分的关系,它将对象组织到树形结构中,最顶层的节点称为 根节点,根节点下面可以包含 树枝节点 和 叶子节点

 C++设计模式——组合模式(Composite Pattern)_c++组合模式-CSDN博客

如果应用的核心模型能用树状结构表示, 在应用中使用组合模式才有价值。

总结:

以上就是当前时代在项目开发中常用到的设计模式,那些没有写在文章种的设计模式,都是在当前开发环境中不怎么常用的,就比如说数据结构中的迭代器模式就在c++11提供的更为灵活的模板迭代器后被取代,备忘录模式也被一些序列化的方案所替代.....反正出于种种原因吧。

还有学习设计模式前最为重要的一点,要具有一定的项目经验。没有项目经验来学习设计模式,就像 “水中花,镜中月” 一样,不能深刻的体会到设计模式的真正用处,这也就背离了学习设计模式的初衷——个人理解“ 学习设计模式的目的就在于,提高代码的可重用性、可扩展性和可维护性,降低依赖和耦合。我相信,如果拥有一种好的代码设计能力,在日后的职业生涯里应该也会大有裨益的吧

文章中设计模式的代码:

pengjingbo/Designed_Pattern: 这是很多常用的设计模式的实现代码,着重于设计模式逻辑的处理 (github.com)

  • 12
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值