java-designPatterns

https://www.bilibili.com/video/BV1RC4y1H7ok/?p=2
https://gitee.com/lixl/web-demo.git

23种设计模式

  • 创建型

    • singleton
    • factory method
    • abstract factory
    • builder
    • prototype
  • 结构型

    • adapter
    • bridge
    • composite
    • decorater
    • facade
    • flyweight
    • proxy
  • 行为型

    • chain of responsibility
    • command
    • interpreter
    • iterator
    • mediator
    • memento
    • observer
    • state
    • strategy
    • template method
    • visitor

单例模式singleton

静态方法单例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
package com.p1;

/**
* 饱汉单例
*
*/
public class M1 {

private static final M1 instance = new M1();

private M1(){

}

public static M1 getInstance(){

return instance;
}

}

静态内部类单例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
package com.demo.p1;

/**
* 静态内部类实现单例
*/
public class M2 {

//隐藏构造方法
private M2(){
System.out.println(111);//不管
}

public static M2 getInstance(){
return M2Inner.getM2();
}

public void execute(){
//
// System.out.println("eeee");
}

private static class M2Inner{

private static M2 m2 = new M2();

private M2Inner(){

}

public static M2 getM2(){

return m2;
}

}

}

DCL单例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
package com.p1;

/**
* 懒加载-DCL
* 1.synchronized保证多线程下只创建一个实例
* 2.volatile 保证不发生指令重排(JIT发生重排时会导致获取的instance为空)
3.对象创建半初始化
*/
public class M2 {

private static volatile M2 instance = null;

private M2(){

}

public static M2 getInstance(){
if(instance == null){
synchronized (M2.class){
if(instance==null){
instance = new M2();
}
}
}
return instance;
}

}

枚举单例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
package com.p1;

/**
* 用枚举实现单例
* Effect java推荐的方法
*/
public enum M3 {

INSTANCE;

public void doSomething(){
System.out.println(1111);
}

public static void main(String[] args) {
M3.INSTANCE.doSomething();
}

}

spring-bean单例

Spring创建Bean的scope(prototype/singleton)默认为singleton
org.springframework.beans.factory.support.DefaultListableBeanFactory#preInstantiateSingletons

策略模式strategy

  • java.util.Comparator接口
    java.util.Arrays.sort(T[] a, Comparator<? super T> c)
    java.util.Collections.sort(List<T> list, Comparator<? super T> c)

实现两种策略(通过年龄和重量两种属性排序),通过sort方法调用后给数组排序

classDiagram
    class java_util_Arrays
    java_util_Arrays: +sort(T[] t, Comparator c)

    class Comparator
    <> Comparator
    Comparator: +compare(Object o1, Object o2) int

    java_util_Arrays o-- Comparator

    class AnimalAgeComparator
    AnimalAgeComparator: +compare(Object o1, Object o2) int

    class AnimalWeightComparator
    AnimalWeightComparator: +compare(Object o1, Object o2) int

    AnimalAgeComparator ..|> Comparator : impl
    AnimalWeightComparator ..|> Comparator : impl

    class Main
    Main: +execute()

    Main ..> java_util_Arrays : invoke

工厂模式factory

1.能生成对象的类或者方法,都是工厂
2.单例也是一种工厂模式
3.比直接用new创建对象好,可以控制对象的生成过程

  • 简单工厂
    与策略模式类似,工厂生产不同的种类的产品,方便控制不同产品生产过程

  • 静态工厂

  • 工厂方法

  • 抽象工厂
    不直接生产产品,而是调用抽象工厂生产抽象的产品(好像是对不同类型但有些相同点的产品都用抽象工厂来生产)

  • spring IOC
    spring-BeanFatory

门面模式/调停者模式

如消息中间件,可以给各个组件解耦

装饰器模式

1.增强某个类的功能,与代理模式相同

观察者模式 observer

1.Observer、Listener、Hook、Callback、js event 都是观察者模式

2.以事件监听器为例理解
SourceEvent 事件源对象,由事件产生
EventListener 事件监听者(可以有多个),接收事件源并处理
EventObserver 事件观察者,把事件源对象传递给监听者

组合模式 composite

封装树形结构的节点
如文件:File(file/directory)

享元模式 flywight

1.共享元对象,不重新创建多个小对象了
2.池化思想,如数据库连接池、jvm字符串常量池
3.结合composite,如图形组合

责任链 responsibility-chain

单向链

验证用户是否有权限时,要依次经过多个不同类型权限验证(AuthHandler);
某一个验证有权限时就停止同时返回true,直到最后一个验证器。

时序图:

sequenceDiagram
    autonumber
    AuthHandler1-->>AuthHandler2: UserSubject
    AuthHandler2-->>AuthHandler3: UserSubject

类图:

classDiagram
    class UserSubject
    UserSubject: +userId
    UserSubject: +userType
    UserSubject: +group...

    class AuthHandler
    <> AuthHandler
    AuthHandler: +doValidate(UserSubject userSubject) boolean

    AuthHandler1 ..|>  AuthHandler : impl
    AuthHandler2 ..|>  AuthHandler : impl
    AuthHandler3 ..|>  AuthHandler : impl

    class AuthHandlerChain
    AuthHandlerChain: +authHandlerList List
    AuthHandlerChain: +addAuthHandler(AuthHandler authHandler) AuthHandlerChain
    AuthHandlerChain: +doValidate(UserSubject userSubject) boolean

    AuthHandlerChain ..|>  AuthHandler : impl

    class Main
    Main: authHandlerChain.add(authHandler1).add(authHandler2).add(authHandler3)
    Main: authHandlerChain.doValidate(userSubject)

双向链

例如,tomcat的 Filter/FilerChain , SpringMVC的 HandlerInterceptor

时序图

sequenceDiagram
    autonumber
    Filter1-->>Filter2: request
    Filter2-->>Filter3: request
    Filter3->>Servlet: request
    Servlet->>Filter3: response
    Filter3-->>Filter2: response
    Filter2-->>Filter1: response

类图:

classDiagram
    class Filter
    <> Filter
    Filter: +doFilter(request, response, filterChain)

    class FilterChain
    FilterChain: -p int
    FilterChain: +doFilter(request, response, filterChain)

    Filter1 ..|>  Filter : impl
    Filter2 ..|>  Filter : impl

代理模式

静态代理

通过代理类去调用代理对象方法

classDiagram

class Movable
<> Movable
Movable: +doMove()

class Tank
Tank: +doMove()

Tank ..|>  Movable : impl

class TankLogProxy
TankLogProxy: -m:Movable
TankLogProxy: +doMove()

TankLogProxy ..|>  Movable : impl

class TankTimeProxy
TankTimeProxy: -m:Movable
TankTimeProxy: +doMove()

TankTimeProxy ..|>  Movable : impl

class Person
Person: -name
Person: +dirveTank()

动态代理

静态代理缺点:Proxy类需要明确实现Movable接口,不方便切换为其他类型。
如,已经实现好的一个TankLogProxy来打印日志,要想给或者Person也打印日志的话,需要重新实现LogProxy了.

使用jdk动态代理实现:被代理类要通过接口实现

classDiagram

class Movable
<> Movable
Movable: +doMove()

class Tank
Tank: +doMove()

class Person
Person: -name
Person: +eat()
Person: +doMove()

class LogProxy
LogProxy: -target Object
LogProxy: invoke(Object proxy, Method method, Object[] args) Object

Tank ..|>  Movable : impl
Person ..|>  Movable : impl
LogProxy ..|>  InvocationHandler : impl
Person o-- LogProxy
Tank o-- LogProxy

cglib动态代理实现:被代理接口不需要接口

AOP

spring, aspect oriented programming 面向切面编程

切面:一组代理对象,组成一个切面
切入点:被调用的一个或多个方法,组成一个切入点
织入:从切入点出插入切面的操作,叫织入

通过接口实现的类 ==> jdk动态代理 ==》动态生成代理类,通过代理类来调用方法执行
被代理类(注意不能为final) ==> cglib(asm) ==》动态生成被代理的子类,通过子类来执行方法

迭代器(Iterator)

Array
LinkedList
Collection
Iterator ==>
hasNext():boolean
next():Object

访问者模式(Visitor)

适合内部结构固定的模型
AST(abstract syntex tree 抽象语法树)
Tomcat(server.xml)
asm(class)

构造器(builder)

分步构造一个复杂对象,每个构造器构造复杂对象的一部分,最好拼接起来

classDiagram

class Product
Product: +part1
Product: +part2
Product: +part3

class Builder
<> Builder
Builder: +buildPart1() Builder
Builder: +buildPart2() Builder
Builder: +buildPart3() Builder
Builder: +build() Product

class SimpleBuilder
SimpleBuilder: -product Product
SimpleBuilder: +buildPart1() Builder
SimpleBuilder: +buildPart2() Builder
SimpleBuilder: +buildPart3() Builder
SimpleBuilder: +build() Product

class ComplextBuilder
ComplextBuilder: -product Product
ComplextBuilder: +buildPart1() Builder
ComplextBuilder: +buildPart2() Builder
ComplextBuilder: +buildPart3() Builder
ComplextBuilder: +build() Product

SimpleBuilder ..|>  Builder : impl
ComplextBuilder ..|>  Builder : impl
Builder ..> Product : create

适配器模式(adapter)

适配两种不同的类型

classDiagram

class FileInputStream
FileInputStream: +read()

class InputStreamReader
InputStreamReader: +read()


class BufferedReader
BufferedReader: +readLine()

FileInputStream -- InputStreamReader
InputStreamReader -- BufferedReader
FileInputStream .. BufferedReader : 不能直接访问

桥接模式(bridge)

m-n m/n都有多种的时候,使用桥接模式,避免类爆炸

classDiagram

class MClazz
MClazz: +NClazz
MClazz: +get() MNClazz

class NClazz1
NClazz1: +exec1()

class NClazz2
NClazz2: +exec2()

class NClazz3
NClazz3: +exec3()

NClazz1 ..|>  NClazz : extends
NClazz2 ..|>  NClazz : extends
NClazz3 ..|>  NClazz : extends

MClazz *-- NClazz : Composition

命令模式(command)

classDiagram

class Command
<> Command
Command: -content StringBuilder
Command: +redo()
Command: +undo()


InsertCommand --|> Command
RedoCommand --|> Command
UndoCommand --|> Command
  • 多个命令组成大的命令:composite(组合)
  • 多次redo命令:chain responseribility(责任链)
  • trasaction回滚:记忆

原型模式(prototype)

Object.clone() ==> Cloneable

  • 浅copy:引用类型只copy对象地址
  • 深copy:被引用对象实现cloneable接口,组合对象clone方法调用成员对象的clone对象

哪些对象需要注意clone

  • 基本数据类型 不需要
  • String 不需要,都是使用的常量池
  • StringBuilder/StringBuffer 也需要复制一份
  • 引用对象 必须实现clone方法

备忘录模式(memento)

记录快照 –> 对象序列化(反序列化)
serizliable
transient

模板方法(TemplateMethod)

钩子函数

状态模式(state)

swatch case ==转换==> 多个子类

  • 有限状态机
    Thread state

解释器(Intepreter)

动态脚本解释

6大设计原则

solid稳定的 记忆首字母

单一原则(Single Responsibility Principle)

一个类或者一个方法只负责一项职责,尽量做到类的只有一个行为原因引起变化

开闭原则(open closed principle)

用抽象构建架构,用实现扩展原则

里氏替换原则(LSP liskov substitution principle)

子类可以扩展父类的功能,但不能改变原有父类的功能

迪米特原则(law of demeter LOD)

最少知道原则,尽量降低类与类之间的耦合;

一个对象应该对其他对象有最少的了解

接口隔离(interface segregation principle)

建立单一接口;(扩展为类也是一种接口,一切皆接口)

定义:
a.客户端不应该依赖它不需要的接口;
b.类之间依赖关系应该建立在最小的接口上;

简单理解:复杂的接口,根据业务拆分成多个简单接口;(对于有些业务的拆分多看看适配器的应用)

【接口的设计粒度越小,系统越灵活,但是灵活的同时结构复杂性提高,开发难度也会变大,维护性降低】 

依赖倒置原则(dependence inversion principle)

面向接口编程;(通过接口作为参数实现应用场景)

抽象就是接口或者抽象类,细节就是实现类

含义:
上层模块不应该依赖下层模块,两者应依赖其抽象;
抽象不应该依赖细节,细节应该依赖抽象;

通俗点就是说变量或者传参数,尽量使用抽象类,或者接口;
【接口负责定义public属性和方法,并且申明与其他对象依赖关系,抽象类负责公共构造部分的实现,实现类准确的实现业务逻辑】