0
点赞
收藏
分享

微信扫一扫

我应该理解的一些设计模式(看情况持续更新)

辰鑫chenxin 2022-02-24 阅读 101

1 概述

1.1 为什么学习设计模式

看懂源代码:懂了设计模式去看目前市面上常见的一些框架就比较容易了

看到前辈的代码:前辈们在开发时也是使用设计模式的

编写自己理想中的代码

1.2 什么是设计模式

使用设计模式最终的目的是实现代码的 高内聚低耦合

  1. 内聚 :块内联系,指模块的功能强度的度量,即一个模块内部各个元素彼此结合的紧密程度的度量。
  2. 耦合:是对模块间关联程度的度量。耦合的强弱取决与模块间接口的复杂性、调用模块的方式以及通过界面传送数据的多少。

解决软件开发某些特定问题而提出的一些解决方案,也可以理解成解决问题的一些思路

增强代码的可重用性、可扩充性、 可维护性、灵活性

2 设计模式的6大原则

2.1 开闭原则(Open Close Principle)

尽量通过扩展软件实体来解决需求变化,而不是通过修改已有的代码来完成变化

如果要修改代码尽量用继承或组合的方式来扩展类的功能,而不是直接修改类的代码。

2.2 里氏代换原则(Liskov Substitution Principle)

把父类设计为抽象类或者接口,让子类继承父类或实现父接口,子类可以扩展父类的功能,但不能改变父类原有的功能。

  1. 子类可以扩展父类的功能,但不能改变父类原有的功能
  2. 子类可以实现父类的抽象方法,但不能覆盖父类的非抽象方法,
  3. 子类中可以增加自己特有的方法。

里氏代换原则是开闭原则的具体实现手段之一。

2.3 单一职责原则(Single Responsibility Principle)

一个方法只负责一件事情。

2.4 接口隔离原则(Interface Segregation Principle)

接口中的方法应该尽量少。

  1. 使用多个隔离的接口,比使用单个接口要好。
  2. 单一职责针对的是类
  3. 接口隔离针对的是接口

2.5 依赖倒转原则(Dependence Inversion Principle)

核心思想是面向接口编程.

要依赖抽象,不要依赖具体类

不能让高层组件依赖底层组件,而且高层组件和低层组件都应该依赖抽象

2.6 迪米特法则(最少知道原则)(Demeter Principle)

有两个少:

  1. 类向外公开的方法应该尽可能的少
  2. 依赖的对象尽可能的少(只依赖应该依赖的对象)

3 设计模式的分类

在这里插入图片描述
重点记住:工厂方法模式、抽象工厂模式、单例模式、原型模式

4 模式说明

4.1 单例模式

基础认识

意图:保证一个类仅有一个实例,并提供一个访问它的全局访问点

主要解决:一个全局使用的类频繁地创建与销毁

何时使用:当您想控制实例数目,节省系统资源的时候。

实例:

  1. 一个班级只有一个班主任
  2. Windows 是多进程多线程的,在操作一个文件的时候,就不可避免地出现多个进程或线程同时操作一个文件的现象,所以所有文件的处理必须通过唯一的实例来进行
  3. 一些设备管理器常常设计为单例模式,比如一个电脑有两台打印机,在输出的时候就要处理不能两台打印机打印同一个文件

优缺点

优点:

  1. 在内存里只有一个实例,减少了内存的开销,尤其是频繁的创建和销毁实例(比如管理学院首页页面缓存)。
  2. 避免对资源的多重占用(比如写文件操作)。

缺点:

  1. 没有接口,不能继承,与单一职责原则冲突,一个类应该只关心内部逻辑,而不关心外面怎么样来实例化。

单例创建方式(饿汉式和懒汉式)

饿汉式:类初始化时,会立即加载该对象线程天生安全,调用效率高

懒汉式: 类初始化时,不会初始化该对象,真正需要使用的时候才会创建该对象,具备懒加载功能

4.2 工厂模式

基础认识

意图:定义一个创建对象的接口,让其子类自己决定实例化哪一个工厂类工厂模式使其创建过程延迟到子类进行

主要解决:主要解决接口选择的问题

何时使用:我们明确地计划不同条件下创建不同实例时

如何解决:让其子类实现工厂接口,返回的也是一个抽象的产品。

关键代码:创建过程在其子类执行

应用实例:

  1. 您需要一辆汽车,可以直接从工厂里面提货,而不用去管这辆汽车是怎么做出来的,以及这个汽车里面的具体实现。
  2. Spring和Mybatis的源码
  3. 在Spring IOC容器创建bean的过程是使用了工厂设计模式
  4. Spring中无论是通过xml配置还是通过配置类还是注解进行创建bean,大部分都是通过简单工厂来进行创建的。

优缺点

优点:

  1. 一个调用者想创建一个对象,只要知道其名称就可以了。
  2. 扩展性高,如果想增加一个产品,只要扩展一个工厂类就可以。
  3. 屏蔽产品的具体实现,调用者只关心产品的接口
  4. 工厂模式是我们最常用的实例化对象模式了,是用工厂方法代替new操作的一种模式
  5. 降低程序的耦合性,为后期的维护修改提供了很大的便利。

缺点:

  1. 每次增加一个产品时,都需要增加一个具体类和对象实现工厂,使得系统中类的个数成倍增加,在一定程度上增加了系统的复杂度,同时也增加了系统具体类的依赖。这并不是什么好事。

工厂模式分类

简单工厂 :用来生产同一等级结构中的任意产品。(不支持拓展增加产品)

工厂方法 :用来生产同一等级结构中固定产品。(支持拓展增加产品)

抽象工厂 :用来生产不同产品族全部产品。(不支持拓展增加产品;支持增加产品族

4.3 代理模式

基础认识

意图:为其他对象提供一种代理以控制对这个对象的访问

主要解决:

  1. 在直接访问对象时带来的问题,

  2. 直接访问会给使用者或者系统结构带来很多麻烦,我们可以在访问此对象时加上一个对此对象的访问层。

何时使用:想在访问一个类时做一些控制

如何解决:增加中间层

关键代码:实现与被代理类组合

应用实例:

  1. Windows 里面的快捷方式。
  2. 猪八戒去找高翠兰结果是孙悟空变的,可以这样理解:把高翠兰的外貌抽象出来,高翠兰本人和孙悟空都实现了这个接口,猪八戒访问高翠兰的时候看不出来这个是孙悟空,所以说孙悟空是高翠兰代理类。
  3. 买火车票不一定在火车站买,也可以去代售点。
  4. 一张支票或银行存单是账户中资金的代理。支票在市场交易中用来代替现金,并提供对签发人账号上资金的控制。
  5. spring aop、日志打印、异常处理、事务控制、权限控制等

优缺点

优点:

  1. 职责清晰。
  2. 高扩展性。
  3. 智能化。

缺点:

  1. 由于在客户端和真实主题之间增加了代理对象,因此有些类型的代理模式可能会造成请求的处理速度变慢
  2. 实现代理模式需要额外的工作,有些代理模式的实现非常复杂。

代理的分类

静态代理(静态定义代理类):简单代理模式,是动态代理的理论基础。常见使用在代理模式

动态代理(动态生成代理类,也称为Jdk自带动态代理):使用反射完成代理。需要有顶层接口才能使用,常见是mybatis的mapper文件是代理。

Cglib 、javaassist(字节码操作库):也是使用反射完成代理,可以直接代理类(jdk动态代理不行),使用字节码技术,不能对 final类进行继承。(需要导入jar包)

4.4 原型模式

基础认识

意图:用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象。简单来说就是克隆

主要解决:在运行期建立和删除原型

应用实例:

  1. 细胞分裂。
  2. JAVA 中的 Object clone() 方法

原型模式分为浅复制和深复制

(浅复制)只是拷贝了基本类型的数据,而引用类型数据,只是拷贝了一份引用地址

(深复制)在计算机中开辟了一块新的内存地址用于存放复制的对象。

优缺点

优点:

  1. 性能提高。
  2. 逃避构造函数的约束。

缺点:

  1. 配备克隆方法需要对类的功能进行通盘考虑,这对于全新的类不是很难,但对于已有的类不一定很容易,特别当一个类引用不支持串行化的间接对象,或者引用含有循环结构的时候。
  2. 必须实现 Cloneable 接口

4.5 建造者模式

基础认识

意图:将一个复杂的构建与其表示相分离,使得同样的构建过程可以创建不同的表示

主要解决:主要解决在软件系统中,有时候面临着"一个复杂对象"的创建工作,其通常由各个部分的子对象用一定的算法构成;由于需求的变化,这个复杂对象的各个部分经常面临着剧烈的变化,但是将它们组合在一起的算法却相对稳定。

何时使用:一些基本部件不会变,而其组合经常变化的时候

如何解决:将变与不变分离开

关键代码:

  1. 建造者:创建和提供实例,
  2. 导演:管理建造出来的实例的依赖关系。

应用实例:

  1. 去肯德基,汉堡、可乐、薯条、炸鸡翅等是不变的,而其组合是经常变化的,生成出所谓的"套餐"。
  2. JAVA 中的 StringBuilder

优缺点

优点:

  1. 建造者独立,易扩展。
  2. 便于控制细节风险。

缺点:

  1. 产品必须有共同点,范围有限制。
  2. 如内部变化复杂,会有很多的建造类。

4.6 模板模式

基础认识

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

主要解决:一些方法通用,却在每一个子类都重新写了这一方法

何时使用:有一些通用的方法

如何解决:将这些通用算法抽象出来

关键代码:在抽象类实现,其他步骤在子类实现。

应用实例:

  1. 在造房子的时候,地基、走线、水管都一样,只有在建筑的后期才有加壁橱加栅栏等差异。
  2. 西游记里面菩萨定好的 81 难,这就是一个顶层的逻辑骨架。
  3. spring 中对 Hibernate 的支持,将一些已经定好的方法封装起来,比如开启事务、获取 Session、关闭 Session 等,程序员不重复写那些已经规范好的代码,直接丢一个实体就可以保存。

优缺点

优点:

  1. 封装不变部分,扩展可变部分。
  2. 提取公共代码,便于维护。
  3. 行为由父类控制,子类实现。

缺点:每一个不同的实现都需要一个子类来实现,导致类的个数增加,使得系统更加庞大

举报

相关推荐

0 条评论