设计模式笔记

2021-10-04  本文已影响0人  逆臣可以改

创建型模式

单例模式 Singleton

概念

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

适用性

在内存中,如果需要某个类的对象,在程序上保证,有且只有一个该类的对象

例子

  1. 上锁
    给静态获得实例方法加上synchronized关键字,锁住的是这个类,效率下降。
  2. 锁代码块
    不给静态方法加,而是在判空之后的创建实例的语句块前后加。但是创建语句这两行之间,也存在线程竞争的问题。
  3. 双判空
    代码块加锁之后,再进行一次实例的判空,以防加锁前已经有线程对该变量进行操作。
    要用volatile修饰实例变量,volatile保证可见性,防止指令重排序。如果不用的话,该对象在加锁内部判空之后,进行创建时,由于new关键字的创建过程(分配内存,创建实例[默认值,并未初始化],进行初始化),可能第二步就被其他线程访问(判空时此时不为空)并返回了,此时未完成初始化。
  4. 静态内部类
    静态内部类中,创建该类的final static型的实例。
    加载时,不会加载内部类,可以实现懒加载。
  5. 枚举单例
    可以解决线程同步,也可以防止反序列化。

抽象工厂模式 Abstract Factory

概念

提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类

用法

任意定制产品一族 (一系列)
一个抽象工厂,含有不同族的具体工厂,可以创建不同的系列。而具体系列会随着族的改变而改变

例子

我有一个抽象工厂,有一套方法,但是没有实现,我也不知道我会创建出什么内容。我有若干子类工厂,和我有相同的这套方法,不同的子类工厂,会有不同系列的该套方法的实现方式。


抽象工厂.png

工厂方法 Factory Method

概念

提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类

用法

任意定制生产过程创建某某具体实例的工厂类,含有该类的实例的创建方法。如,XXXFactory.craete(),通过工厂的不同创建方法去完成不同实例的创建。

例子

我有一个工厂接口,含有创建食物的方法,但是我不实现。我有3种工厂子类/实现类,它们也有创建食物方法,是具体的特定的食物。那么我在获得该工厂时可以指定获得哪个子工厂,交由子工厂去完成创建这一过程。

建造者模式

概念

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

作用

分离复杂对象的构建和表示;同样的构建过程可以创建不同的表示。
建造者模式是在当创建复杂对象的算法应该独立于该对象的组成部分以及它们的装配方式时适用的模式

例子

Person类含有一个personBuilder的构建类,内涵一Person成员变量;
含有不同的赋予Persion属性的方法,返回的是PersonBuilder这个类。
最后用build()方法将该Person类返回出去。

原型模式

概念

用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象。

例子

Java的客隆clone()
原型模式需要实现标记型接口Cloneable,一般会重写clone()方法,如果只是重写clone()方法而未实现接口,调用会报异常。一般用于一个对象的属性已经确定,需要产生很多相同对象的时候。
深克隆与浅克隆
原类中的属性,也要进行克隆,开辟一块新的内存,而不是指向之前对象的内存。这个时候克隆前后的两个成员属性就不会相等了。
但是String 类型,不会被深克隆,String类型的成员属性克隆后依然是原来那个String。如果用的是StringBuilder类型,克隆时不对该类型做克隆方法的重写,那么依然指向的是原来那个StringBuilder,类似于原来那个成员属性。
如果克隆对象含有复杂成员对象,那么也要重写该成员对象对应类的clone方法,让它克隆时去自己开辟内存而非指向原油对象的那块内存地址。


客隆模式.png

结构型模式

适配器模式 Adapter

概念

将一个类的接口转换为客户希望的另一个接口。使得原本由于接口不兼容而不能一起工作的那些类可以一起工作。

适用场合

例子

Java.io包中,FileInputStream,获得文件的输入流,是按字节读取的;InputStreamReader,将文件字节输入流转化为字符输入流;BufferedRead,将字符输入流转化为可缓冲的,按行读取的流。
微软的ODBC,可以使用桥接方法转化为JDBC供Java访问SQL Server。


适配器模式.png

桥接模式 Bridge

概念

将抽象部分与它的实现部分分离,使它们都可以独立地变化

理解

双维度扩展;
分离抽象与具体,用聚合的方式连接抽象和具体。
实现,指的是抽象类和它的派生类用来实现自己的对象。

实现系统可能有多角度分类,每一种分类都可能变化,那么把这种多角度分离出来,让它们独立变化,减少它们之间的耦合。

例子

比如把人进行分类,按性别分类可以分为男女;按照职业分类可以分为运动员与艺术家;如果在男人类下面再分为难艺术家和女艺术家,那么当职业分类有新扩展时,要重写男人类,也要重写女人类。但是,人这个父类,可以拥有一个叫做职业的子类,扩展的时候只要想职业子类增加其他具体职业;从另一个性别类的维度看,即当前性别的人可以拥有/持有职业这么一重身份,也就是成员属性,实现【用聚合代替继承】,只需要传递进来即可。再职业类进行扩展而不会影响性别类的内部结构。

组合模式 Composite

组合模式可以让客户一致地使用组合结构体和单个对象。

概念

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

例子

打印的时候如果是分支节点则递归地调用分支节点中的tree()方法,完成文件结构的展示

使用场合

需求中使体现部分与整体层次时的结构时,以及希望用户可以忽略组合对象与单个对象的不同,同一地使用组合结构中的所有对象时。


组合模式.png

装饰器模式 Decorator

用聚合替代继承
向装饰者类传递一个基础类,可以丰富或者说增强基础类的一些同名方法。

概念

动态地给一个对象添加一些额外的职责,就增加功能来说,装饰者模式比生成子类更加灵活。

特点

例子

在Java的IO流中,Reader类 聚合了一个 InputStream。


装饰者模式.png

分离每个装饰对象的实现和使用,每个装饰对象只关心自己的功能,不需要关心如何被添加到对象链当中。

门面模式 Facade

概念

为子系统中的一组接口提供一个一致的界面,此模式定义了一个高层接口,这个接口使得这一子系统更加容易使用

用途

使用场合

  1. 设计初期,将架构分层,如MVC的层与层之间建立外观Facade。
  2. 开发节点,子系统因重构而变复杂,增加外观Facade可以提供一个简单的接口,减少依赖
  3. 维护遗留的大型系统,开发Facade类,为设计粗糙或高度复杂的遗留代码提供比较清晰的借口,让新系统与Facade对象交互,Facade与遗留代码交互所有复杂的工作。

享元模式 Flyweight

概念

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

理解

共享元数据,把数据放到一个大池子里下次不需要再创建只需要去池子里拿

例子

String类型 的intern()方法,获得该字符串对象在常量池中的引用,如果字面量相等,那么从池中获得的是同一个引用

代理模式 Proxy

概念

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

例子

  1. jdk动态代理必须面向接口,调用Proxy类的newInstance方法创建代理对象,传递被代理对象的类加载器,接口数组和调用处理器(传递被代理对戏,重写其invoke方法,动态实现方法增强)
  2. cglib动态代理则面向类(待补充)
代理模式.png

行为模式

命令模式 Command

概述

将一个请求封装为一个对象,从而使你可用不同的请求对客户进行参数化;对请求排队或者记录请求日志,以及支持可撤销的操作。

适用性

责任链模式 Chain of Responsibility

概述

使多个对象都有机会处理请求,从而避免请求的发送者和接受者之间的耦合关系。将这些对象连成一条链,并沿着这条链传递该请求,直到有一个对象处理它为止。这一模式的想法是,给多个对象处理一个请求的机会,从而解耦发送者和接受者。

适用性

类图

责任链模式.jpg

链对象持有一个集合,用于存放不同的接收器,可以向链对象添加两个具体的过滤器接收器,完成不同的过滤功能。当需求来时,链会遍历旗下所有的接收器,执行处理功能,而接收器也可以是一个链对象。类似广义数组。

解析器模式 Interpretor

概述

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

适用性

当有一个语言需要解释执行,并且你可将该语言中的句子表示为一个抽象语法树时,可使用解释器模式。而当存在以下情况时,该模式效果最好

迭代器模式 Iterator

概述

提供一种方法顺序访问一个聚合对象中的各个元素,而又不暴露该对象的内部表示

适用性

类图

迭代器模式.png

集合接口持有自己的迭代器,具体的集合持有自己的具体的迭代器,在具体迭代器中含有下一个,访问当前元素等方法的具体实现(与容器结构有关)。

中介者模式 Mediator

概念

用一个中介对象来封装一系列的对象交互。中介者使各对象不需要显示地相互引用,从而使其耦合松散,而且可以独立地改变它们之间的交互

适用性

备忘录模式 Momento

概述

在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态。这样以后就可以将该对象恢复到原先保存的状态。

适用性

观察者模式

概念

定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象。这个主题对象在状态发生变化时,会通知所有观察者对象,使它们能够自动更新自己。

组成

事件源对象:含有一揽子观察者(list),含有自己的触发若干观察者的方法,触发之后遍历观察者,传递事件,并调用它们的方法。
观察者对象:观察者接口,含有一些事件的处理方法(将事件传递进来);观察者接口的具体实现类,能够依据传来的事件,完成具体的事件处理方法。
事件:是一个抽象类,又一个获得事件源的钩子方法;对应有一个事件的具体实现列,依据与源对象有关的信息创建具体事件。

状态模式 State

概念

当一个对象的内在状态改变时,允许改变其行为,这个对象看起来像是改变了其类

适用性

主要解决的是当控制一个对象状态转换的条件表达式过于复杂时的情况。把状态的判断逻辑转移到表示不同状态的一系列类中,可以把复杂的判断逻辑简化。
方法会依据状态不同而执行不同的操作,可以将所有操作移交给状态类再去执行,状态类要有客户类中的所有方法。
TCP会根据连接的不同状态,比如Established,Listen,Closed,而对操作Open(),Close(),Acknowledge()有不同的具体执行。

策略模式 Strategy

概念

定义了算法家族,分别封装起来,让它们之间可以互相替换,此模式让算法的变化不会影响到使用算法的客户

适用情况

模板方法 Template

概念

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

适用性

访问者模式 Visitor

概念

表示一个作用于某对象结构中的各元素的操作。它使你可以在不改变各类的前提下定义作用于这些元素的新操作

适用性

六大原则

单一职责原则 Single Responsibility Principle

开闭原则 Open-Closed Principle

里式替换原则 Liscov Substitution Principle

依赖倒置原则 Dependency Inversion Principle

接口隔离原则 Interface Segregation Principle

迪米特法则 Law of Demeter

  1. 当前对象本身 this
  2. 以参数形式传入当前对象方法中的对象
  3. 当前对象的成员对象
  4. 如果当前对象的成员对象是一个集合,那么集合中的元素也是朋友
  5. 当前对象所创建的对象
上一篇下一篇

猜你喜欢

热点阅读