23种设计模式之基本介绍

23种设计模式之基本介绍

参考资料

下文如有错漏之处,敬请指正

一、简介

设计模式(Design Pattern)是一套理论,是软件界前辈们代码设计经验的总结,其目的是为了提高代码的可扩展性、可靠性、可重用性和可读性。

使用设计模式,可以使软件具有:

  • 可扩展性(可以非常方便的增加新的功能)
  • 可靠性(当增加新功能后,对原有的功能不产生影响)
  • 可重用性(相同功能的代码,不用多次编写)
  • 可读性(编程规范,便于其他程序员的阅读和理解)

设计模式常用的7大原则:

  1. 单一职责原则 (Single Responsibility Principle)
  2. 接口隔离原则 (Interface Segregation Principle)
  3. 依赖倒转原则 (Dependence Inversion Principle)
  4. 里氏替换原则 (Liskov Substitution Principle)
  5. 开闭原则 (Open/Closed Principle)
  6. 迪米特原则 (Least Knowledge Principe)
  7. 合成复用原则 (Composite Reuse Principle)

二、7大原则

单一职责原则(SRP)

基本介绍
  • 一个类、接口、或方法只负责一项职责,即只做一件事
  • 目的是降低类的复杂度,使每一个类、接口或方法都有一个清晰的定义
场景模拟

如类A负责两个不同的职责:职责1,职责2。当职责1的需求变更而要修改类A时,可能造成职责2执行错误,所以需要将类A的粒度分解为 类A1(包含职责1)和类 A2(包含职责2)。

接口隔离原则(ISP)

基本介绍

一个类对另一个类的依赖应该建立在最小的接口上,即一个类不应该依赖它不需要的接口。

场景模拟

一个接口I有5个功能,类A实现了该接口I,但实际只用到接口I的2个功能,这时类中的另外三个方法就会被浪费,所以需要将接口I的粒度进行分解,将类A需要的两个接口分离出来变为接口X,让类A实现接口X,使类A中的功能全部被使用。

依赖倒转原则(DIP)

基本介绍
  • 高层模块不应该依赖低层模块,二者都应该依赖其抽象
  • 抽象不应该依赖细节,细节应该依赖抽象
  • 依赖倒转的中心思想是面向接口编程
  • 目的是减少类间的耦合性,提高系统的稳定性
场景模拟

每个APP都有页面显示的需求,且每个APP页面显示的内容均不同,手机系统不可能为每个APP页面显示单独开发。因此手机系统自定义一个页面显示功能接口,对显示功能进行规范,让每个APP实现该接口进行页面显示的定制开发。

里氏替换原则(LSP)

基本介绍
  • 父类能出现的地方子类就可以出现,而且替换为子类也不会产生任何错误或异常
  • 里氏替换原则是对继承(OO)的规范
  • 如果父类的某些方法在子类中发生了”畸变“(改变了方法原有的意义),建议断开继承关系,采用依赖、聚合或组合的方式代替继承
  • 子类可以扩展父类的功能,但不能改变父类原有的功能,即子类中尽量不要重写父类的方法
  • 目的是代码共享,减少创建类的工作量和提高代码的可扩展性
场景模式

如一个动物类,其中有一个方法是奔跑。老虎类继承了动物类,老鹰也继承了动物类,但是它不会奔跑,于是它重写了父类的奔跑方法,此时便违反了里氏替换原则。因此要对动物类进行粒度分解,分为飞禽类和走兽类,让老鹰继承飞禽类。

开闭原则(OCP)

基本介绍
  • 一个软件的实体应该对扩展开放,对修改关闭。即一个软件实体应该通过扩展来实现变化,而不是通过修改已有的代码来实现变化。
  • 用抽象构建框架,用实现扩展细节
场景模拟

如有一个主题类,当用户想更换主题时,需要对原有主题类的代码进行更改,这就违反了开闭原则。所以应将主题类设为抽象类,由其子类来定义主题,当需要更换主题时,只要增加一个子类,不改变原有代码结构。

迪米特原则(LKP)

基本介绍
  • 迪米特原则又称为最少知识原则
  • 从依赖者的角度来说,只依赖应该依赖的对象。
  • 从被依赖者的角度说,只暴露应该暴露的方法。
场景模拟

如电影制作公司,当电影制作完成之后交由院线上线,由院线排片出售票务,由院线和用户产生关系,电影制作公司不与用户产生关系。

合成复用原则(CRP)

基本介绍

尽量使用组合或聚合的方式替代继承。

场景模拟

如咖啡店出售的咖啡可以搭配调料,调料有(牛奶,芝士,方糖),如果使用继承的话,就会有一个咖啡父类,咖啡+牛奶类、咖啡+芝士类、咖啡+方糖,每当增加一个调料时,就要增加一个咖啡类+调料类,如果调料非常多,那么将会产生非常多的类。此时可以采用组合或聚合的方法,有一个咖啡父类,在咖啡父类中聚合调料对象,在使用时只需要将调料传入,每当增加一个调料,只需要将调解对象传入,不需要增加新的咖啡类。

7种原则总结

  • 每种原则要求的侧重点不同。
  • 开闭原则是总纲,它告诉我们要对扩展开放,对修改关闭。
  • 里氏替换原则告诉我们不要破坏继承体系。
  • 依赖倒置原则告诉我们要面向接口编程。
  • 单一职责原则告诉我们实现类要职责单一。
  • 接口隔离原则告诉我们在设计接口的时候要精简单一。
  • 迪米特法则告诉我们要降低耦合度。
  • 合成复用原则告诉我们要优先使用组合或者聚合关系,少用继承关系。

三、类与类之间的关系

  • 依赖(虚线箭头)

    • 一个类在类中使用到另一个类,则两个类之间存在依赖关系。

    • 在UML类图中,依赖关系用带箭头的虚线表示,由依赖的一方指向被依赖的一方

    • 如下图所示,Person类依赖Address类
      在这里插入图片描述

  • 泛化 (实线空心)

    • 泛化实际上是继承关系

    • 在UML中,泛化关系用带空心三角形的直线来表示,由子类指向父类

    • 如下图所示,Student与Professor是子类,Person是父类
      在这里插入图片描述

  • 实现(虚线空心)

    • 实现实际上是面向接口编程

    • 在UML中,实现关系用带空心三角形的虚线来表示,由接口实现类指向接口类

    • 如下图所示,Diesel与NEV是接口实现类,Vehicle是接口类
      在这里插入图片描述

  • 关联(实线)

    • 描述类之类间的关系。
      • 单向
        • 1:1
        • 1:n
        • n:1
      • 双向
        • 1:1
        • 1:n
        • n:m
    • 在UML中,关联关系用实线来表示
    • 如下图所示,Person类与Address的关联关系是(1:n)
      在这里插入图片描述
  • 聚合(空心菱形)

    • 整体和部分的关系且整体与部分可以分离,即has-a的关系。
    public class Car{
    private MusicSystem musicSystem; //聚合关系
    }
    
    • 在UML中,聚合关系使用空心菱形表示(菱形指向的是整体),由部分指向整体
    • 如下图所示,Car类聚合MusicSystem类
      在这里插入图片描述
  • 组合(实心菱形)

    • 整体和部分的关系且整体与部分不可以分离,即contains-a的关系。
    public class Car{
     private Engine=new Engine();	//组合关系
    }
    
    • 在UML中,组合关系使用实心菱形表示(菱形指向的是整体),由部分指向整体
    • 如下图所示,Car类组合Engine类
      在这里插入图片描述

四、 设计模式分类

设计模式分为三种类型(创建型、结构型、行为型),共23种。

创建型模式

用于描述“如何创建对象”,它的主要特点是“将对象的创建与使用分离”。

1、 单例模式(Singleton)

一个类只存在一个实例,并且自行实例化并向全局提供一个获取该实例的方法。

2、工厂模式(Factory)

提供一种方法可以通过类或方法产生对象。

3、原型模式(Prototype)

通过克隆原型的实例对象,创建新的对象。

4、建造者模式(Builder)

将一个复杂对象分解成多个相对简单的部分,然后根据不同需求分别创建它们,最后构建成该复杂对象。

5、抽象工厂模式(AbstractFactory)

用来生产固定产品线组成的不同产品族,抽象工厂规定生产的产品集合(即固定产品线),产品集合中的每个产品由抽象工厂的子类工厂(产品族工厂)负责生产。

结构型模式

用于描述如何将类或对象按某种布局组成更大的结构。

1、适配器模式(Adapter)

将一个类的接口转换成客户端期望的另外一个接口,使得原本因接口不兼容的类能协同工作。

2、桥接模式(Bridge)

将抽象与实现分离,使它们可以独立变化。它是用组合关系代替继承关系来实现,从而降低了抽象和实现这两个可变维度的耦合度。

3、装饰者模式(Decorator)

动态的给一个对象增加额外的功能。

4、组合模式(Composite)

将对象组合成树形结构以表示“部分与整体”的层次结构,使得客户端对单个对象和组合对象的使用具有一致性。

5、外观模式(Facade)

为多个复杂的子系统提供一个一致的接口,使调用端可以更加容易的访问这些子系统。

6、享元模式(Flyweight)

运用共享技术来有效地支持大量细粒度对象的复用。

7、代理模式(Proxy)

通过代理类控制目标类的访问。即客户端可以通过代理对象间接地访问目标对象,从而限制、增强或修改目标对象的。

行为型模式

用于描述类或对象之间如何相互协作,共同完成单个对象无法完成的任务,以及如何分配职责。

1、模板方法模式(TemplateMethod)

定义一个算法的框架,封装步骤相同的部分,将特定(不同)步骤的部分交由子类完成,以此达到代码复用。

2、命令模式(Command)

将某个产品的相关操作抽象成命令,由命令连接调用者和实现者,使命令的调用者与命令的实现者分离。

3、访问者模式(Visitor)

在不改变集合元素的前提下,为一个集合中的每个元素提供多种访问方式,即每个元素有多个访问者对象访问。

4、迭代器模式(Iterator)

提供一种方法来顺序访问聚合对象中的一系列数据,而不暴露聚合对象的内部结构。

5、观察者模式(Observer)

多个对象间存在一对多关系,当一个对象发生改变时,把这种改变通知给其他多个对象,从而影响其他对象的行为。

6、中介者模式(Mediator)

定义一个中介对象来封装原有对象之间的交互,使原有对象之间的耦合松散,且可以独立地改变它们之间的交互。即将多对多依赖关系转为一对多,其中一就是中介者。

7、备忘录模式(Memento)

在不破坏封装性的前提下,记录一个对象的内部状态,并在该对象之外保存这个状态,当需要时能将该对象恢复到原先保存的状态。

8、解释器模式(Interpreter)

给定一门语言,定义它的文法表示,再设计一个解析器来解释语言中的句子。

9、状态模式(State)

允许一个对象在其内部状态发生改变时改变其行为。

10、策略模式(Strategy)

定义了一系列算法,并将每个算法封装起来,使它们可以相互替换,且算法的改变不会影响使用算法的客户。

11、责任链模式(Chain of Responsibility)

把请求从链中的一个对象传到下一个对象,直到请求被响应为止。通过这种方式去除对象之间的耦合。

总结

23 种设计模式不是孤立存在的,很多模式之间存在一定的关联关系,在大型系统开发中常常需要同时使用多种设计模式。了解每一种设计模式的特点,做到手中无剑胜有剑。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值