设计模式
设计模式是一套被反复使用的、多数人知晓的、经过分类编目的、代码设计经验的总结。设计模式代表了最佳的实践,通常被有经验的软件开发人员所使用。
- 借助于设计模式可以编写出非常高效的代码,可复用性以及稳健性都会比较强
- 有助于阅读源码框架
设计模式分类
GoF(4人组)设计模式共有23种,根据用途的不同,设计模式可以分为:创建型、结构型、行为型三种。
- 创建型模式
- 由无到有的设计模式,是为了创建应用程序的实例
- 例如:单例模式、工厂模式、建造者模式
- 结构型模式
- 在已有的实例的基础上,做了一些额外的事情
- 例如:代理模式
- 行为型模式

UML类图
UML全称Unified Modeling Language,是用来进行软件设计的可视化建模工具。
见知乎链接:https://zhuanlan.zhihu.com/p/109655171
eg:
1 2 3 4 5 6 7 8 9 10 11 12 13
| public class UserService { private String username; public String password; Integer age;
public void sayUsername(String username) { }
public String bye(String name1, Integer days) { return null; } }
|

设计模式的原则
设计原则按照字母手写简写可以概括为SOLID原则。
- 单一职责原则(
Single Responsibility Principle)
- 让每个类的功能单一 ,尽量使得每个类只负责整个软件的功能模块中的一个
- 开放封闭原则(
Open Close Principle)
- 对新增开发,对修改封闭
- 已有的代码直接进行修改是有很大风险的,如果有新需求,可以在已有的代码进行进一步扩展
- 里氏替换原则(
Liskov Substitution Principle)
- 凡是父类出现的地方,都可以替换为其子类;子类继承父类,尽量不要重写父类的方法
- eg:

- 迪米特法则(
Least Knowledge Principle)
- 又叫作最少知道原则,指的是一个类/模块对于其他的类/模块有越少的了解越好
- 接口分离原则(
Interface Segregation Principle)
- 不要写大接口(大:接口中的方法多),否则会给实现类带来负担
- 依赖倒置原则(
Dependency Inversion Principle)
常用设计模式
创建型设计模式
单例设计模式
- 保证一个类只有一个实例对象,并提供了一个访问该实例对象的全局节点
- eg:在整个应用程序中,如果要获得MySingleton实例,始终获得的都是同一个
- 单例设计模式分为懒汉模式(懒加载)和饿汉模式(立即加载)
- 懒加载:使用的时候才获得实例
- 立即加载:使用之前已经获得实例
- 单例设计模式的设计原则:
-
- 构造方法私有
-
- 定义一个成员变量(私有静态的成员变量),用来接收私有构造方法构造的实例
-
- 提供一个静态方法供外部类调用这个实例
饿汉模式
- 特点:不支持延时加载(懒加载),获取对象速度比较快;但是如果对象比较大,或者一直没有去使用,那么比较浪费内存空间。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
|
public class MySingleton {
private static final MySingleton instance = new MySingleton(); private MySingleton(){}
public static MySingleton getInstance(){ return instance; } }
|
懒汉模式(线程不安全)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
|
public class MySingleton2 { private static MySingleton2 instance;
private MySingleton2() { }
public static MySingleton2 getInstance() { if (instance == null) { instance = new MySingleton2(); } return instance; } }
|
懒汉模式(线程安全)- Synchronized
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| public class MySingleton3 { private static MySingleton3 instance;
private MySingleton3() { }
public static synchronized MySingleton3 getInstance() { if(instance == null){ instance = new MySingleton3(); } return instance; } }
|
懒汉模式(线程安全)- Double Check
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| public class MySingleton4 { private static MySingleton4 instance;
private MySingleton4() {}
public static MySingleton4 getInstance() { if (instance == null) { synchronized (MySingleton4.class) { if (instance == null) { instance = new MySingleton4(); } } } 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
|
public class MySingleton5 {
private MySingleton5() { }
static class Inner { private static MySingleton5 instance;
static { instance = new MySingleton5(); }
private static MySingleton5 getInstance() { return instance; } }
public static MySingleton5 getInstance() { return Inner.getInstance(); } }
|
枚举
1 2 3 4 5 6 7 8
| public enum Singleton6 {
INSTANCE;
public static Singleton6 getInstance(){ return INSTANCE; } }
|
总结
- 饿汉式:在类加载时期,便已经将
instance实例对象创建了;所以这种方式是线程安全的方式,但是不支持懒加载。
- 懒汉式:该种方式支持懒加载,但是要么不是线程安全,要么虽然是线程安全,但是需要频繁释放锁、抢夺锁,并发量较低。
- 双重检查:既可以实现懒加载,又可以实现高并发的需求。这种方式比较完美,但是代码有一些复杂。
- 静态内部类:使用该种方式也可以解决懒加载以及高并发的问题,代码实现起来比双重检查也是比较简洁。
- 枚举:最简单、最完美的实现方式。
工厂设计模式
- 工厂中一定会提供一个返回实例的方法。其中核心的好处是封装(隐藏)生产的具体细节
- 工厂类或接口的命名方式,通常为XXXFactory
简单工厂模式
- 只要一个工厂(函数)就可以了,那么只需要传入不同的参数,就可以返回不同的产品(实例),这种模式就叫简单工厂模式。
- 未满足开闭原则
eg:
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 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56
| public class SimpleFactoryExecution { public static void main(String[] args) { withoutFactory();
withFactory(); }
private static void withFactory() { Scanner scanner = new Scanner(System.in); String s = scanner.nextLine();
SimpleAodiFactory simpleAodiFactory = new SimpleAodiFactory(); Aodi aodi = simpleAodiFactory.create(s); aodi.run(); }
private static void withoutFactory() {
Scanner scanner = new Scanner(System.in); String s = scanner.nextLine(); Aodi aodi = null;
if("A4".equals(s)){ aodi = new A4(); }else if("A5".equals(s)){ aodi = new A5(); }else{ aodi = new Q5(); }
aodi.run(); } }
public class SimpleAodiFactory { public Aodi create(String s){ Aodi aodi = null; if("A4".equals(s)){ aodi = new A4(); }else if("A5".equals(s)){ aodi = new A5(); }else{ aodi = new Q5(); }
return aodi; } }
|
工厂方法模式
- 核心思想:创建工厂接口,增加不同的实现类之后,它里面的工厂方法就是不用的实现
- 要求:把工厂定义为接口或抽象类,通过不同的实现类实现不同实例的生产
eg:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| public interface AodiFactory { public Aodi create(); }
public class A4Factory implements AodiFactory{ @Override public Aodi create() { return new A4(); } }
public class FactoryMethodExecution { public static void main(String[] args) { AodiFactory aodiFactory = new A4Factory(); aodiFactory.create(); } }
|
抽象工厂模式
- 抽象工厂生产的一系列的产品
- 上面两种工厂模式生产的产品比较单一
eg:

建造者设计模式(Builder)
- 开发过程中会遇到这样一个场景,它的名字不叫
XXXBuilder,但是它是采用建造者设计模式的思想来完成
- eg:
StringBuilder是建造者设计模式
- 建造者模式也叫作生成器模式,就是分步骤创建复杂对象
- 建造者设计模式的代码风格:
-
- 首先要创建要生产的实例(仅仅是执行了构造方法)
-
- 会提供很多设置属性值的方法
-
- 会提供返回实例的方法(方法名通常是
build)
eg:
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 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72
| @Data public class Phone { private String battery; private String screen; private String os; private String camera; private String color; }
public class PhoneBuilder { private Phone phone = new Phone();
public PhoneBuilder color(String color) { this.phone.setColor(color); return this; }
public PhoneBuilder battery(String battery) { this.phone.setBattery(battery); return this; }
public PhoneBuilder screen(String screen) { this.phone.setScreen(screen); return this; }
public PhoneBuilder os(String os) { this.phone.setOs(os); return this; }
public PhoneBuilder camera(String camera) { this.phone.setCamera(camera); return this; }
public Phone build() { return this.phone; } }
public class UseBuilder { public static void main(String[] args) { PhoneBuilder builder = new PhoneBuilder(); Phone phone = builder.battery("4000mha") .camera("1080P") .color("尊贵黑") .screen("4K高清") .os("Android") .build(); System.out.println("phone = " + phone); } }
eg:参考StringBuilder的代码风格:
private static void builder1() { StringBuilder sb = new StringBuilder(); sb.append("hello").append(" world").append("!"); String s = sb.toString(); System.out.println(s); }
|
结构型设计模式
代理设计模式(Proxy)
- 增强:满足基本的需求之外,还做了额外的事情(通用的事情)
- 核心特点:
-
- 代理类存在和委托类一样的方法(这个一样指的是外观上)
-
- 代理类执行方法的过程中,一定会执行委托类的方法
- 代理模式最大的优点:
- 可以不更改目标类代码的前提下,扩展目标类代码的功能。
静态代理
- 委托类、目标类(target):
UserServiceImpl
- 代理类:
UserServiceProxy
- 要保证代理类和委托类提供的方法的外观完全一样:
-
- 实现和委托类相同的接口
-
- 继承委托类,重写委托类中的方法
- 代理类中要调用委托类的方法
- 静态代理最大的缺点:
- 代码较为冗余,每代理一个类,便要手动编写一个代理类
- 代理对象和目标类对象均实现了接口,如果接口发生了修改,不仅目标类需要更改,代理类也需要同步发生修改,维护成本变高了很多
eg:
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 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79
| public interface UserService { public int insert(String name);
public int remove(int id); }
public class UserServiceImpl implements UserService{
@Override public int insert(String name) { System.out.println("执行UserServiceImpl的insert方法"); return 0; }
@Override public int remove(int id) { System.out.println("执行UserServiceImpl的remove方法"); return 0; } }
public class UserServiceProxy implements UserService{
private UserService userService = new UserServiceImpl();
@Override public int insert(String name) { int insert = userService.insert(name); return insert; }
@Override public int remove(int id) { int remove = userService.remove(id); return remove; } }
public class UserServiceProxy1 extends UserServiceImpl{ @Override public int insert(String name) { return super.insert(name); }
@Override public int remove(int id) { return super.remove(id); } }
public class Execution { public static void main(String[] args) { withoutProxy();
withProxy(); }
private static void withProxy() { UserService userService = new UserServiceProxy();
userService.insert("1"); }
private static void withoutProxy() { UserServiceImpl userService = new UserServiceImpl(); userService.insert("1"); } }
|
动态代理
- 静态代理的代理类需要自己手动去写,动态代理的代理类不用自己手动去写
- 分类:
JDK动态代理
- 会自动生成代理类,与
UserServiceProxy类似(代理类和委托类实现了相同的接口)
- 效率比较高
- 委托类必须实现接口
cglib动态代理
- 会自动生成代理类,与
UserServiceProxy1类似(代理类继承自委托类)
- 委托类可以不实现接口

JDK动态代理
JDK动态代理,即JDK给我们提供的动态生成代理类的方式,无需引入第三方jar包,但是使用JDK动态代理有一个先决条件,那就是目标类对象必须实现了某个接口;如果目标类对象没有实现任何接口,则JDK动态代理无法使用。
- 生成的代理类中的所有的方法都会指向同一个方法:InvocationHandler的invoke方法,需要程序员来实现InvocationHandler(可以直接写实现类、也可以使用匿名内部类)的invoke方法
eg:
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 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97
| public interface UserService { public String sayHello(String name); }
public class UserServiceImpl implements UserService{ @Override public String sayHello(String name) { String result = "hello " + name; System.out.println(result); return result; } }
@Data public class ProxyGenerator {
Object target;
public Object generator() {
UserService proxy = (UserService) Proxy.newProxyInstance (ProxyGenerator.class.getClassLoader(), UserServiceImpl.class.getInterfaces(), new CustomInvocationHandle(target)); proxy.sayHello("zs");
return proxy; }
public Object generator2() { UserService proxy = (UserService) Proxy.newProxyInstance (ProxyGenerator.class.getClassLoader(), UserServiceImpl.class.getInterfaces(), new InvocationHandler() { @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { Object invoke = method.invoke(target, args); return invoke; } }); return proxy; } }
@AllArgsConstructor @NoArgsConstructor public class CustomInvocationHandle implements InvocationHandler {
Object instance;
@Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("开启事务"); Object invoke = method.invoke(instance, args); System.out.println("关闭事务");
return invoke; } }
public class JdkProxyExecution { public static void main(String[] args) { UserService userService = new UserServiceImpl(); ProxyGenerator proxyGenerator = new ProxyGenerator(); proxyGenerator.setTarget(userService); UserService proxy = (UserService) proxyGenerator.generator();
UserService proxy2 = (UserService) proxyGenerator.generator2();
proxy.sayHello("zs"); } }
开启事务 hello zs 关闭事务 开启事务 hello zs 关闭事务
|
cglib动态代理
- 生成的代理类中的所有的方法都会指向同一个方法:InvocationHandler的invoke方法,需要程序员来实现InvocationHandler(可以直接写实现类、也可以使用匿名内部类)的invoke方法
- 主要原因在于
Cglib扩展的代理类会继承自目标类。所以这也要求我们的目标类不能是final修饰。
eg:
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
| @AllArgsConstructor @NoArgsConstructor @Data public class CglibProxyGenerator { Object target;
public Object generator(){ Object proxy = Enhancer.create(UserServiceImpl.class, new InvocationHandler() { @Override public Object invoke(Object o, Method method, Object[] objects) throws Throwable { System.out.println("开始事务"); Object invoke = method.invoke(target, objects); System.out.println("结束事务"); return invoke; } }); return proxy; } }
public class CglibProxyExecution { public static void main(String[] args) { CglibProxyGenerator generator = new CglibProxyGenerator(); generator.setTarget(new UserServiceImpl());
UserService proxy = (UserService) generator.generator(); proxy.sayHello("zs"); } }
开始事务 hello zs 结束事务
|
动态代理小结:
- 代理类中一定会包含和委托类外观一致的方法,该方法中一定会有委托类方法的调用
- 静态代理:(
instance、super调用)
- 动态代理:
method.invoke
- JDK动态代理的委托类一定要实现接口,JDK代理对象只能使用接口来接收(猫不能接收狗)
- Cglib动态代理,接口和实现类都可以接收
- 使用动态代理,所有的方法都会指向
InvocationHandler的invoke方法
- 真正需要程序员开发的内容:提供InvocationHandler的实现类(定义实现类或匿名内部类),实现其中的invoke方法
- 动态代理的优势在于:实现方法的通用的增强,把委托类中出现的相同的内容给提取出来
面试问题:代理类和委托类之间的关系是什么? 分JDK动态代理和Cglib动态代理两方面回答
行为型设计模式
责任链
责任链是一种行为设计模式,允许请求沿着链进行发送。收到请求后,每个处理者均可对请求进行处理或者将其传递给链上的下一个处理者。
eg:
将一些共性的部分放置在一个基类中,其中提供的成员变量next能够维护顺序关系,通过调用其提供的setNext方法完成顺序关系的维护,handle方法能够提供不同的
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 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85
| @Data public abstract class AbstractHandler { AbstractHandler next; public void handle(){ handleCore(); if (next != null) { next.handle(); } }
protected abstract void handleCore(); }
@Data public class Handler1 extends AbstractHandler {
public void handleCore() { System.out.println("Handler1的handle"); } }
@Data public class Handler2 extends AbstractHandler {
public void handleCore() { System.out.println("Handler2的handle"); } }
@Data public class Handler3 extends AbstractHandler {
public void handleCore() { System.out.println("Handler3的handle"); } }
public class ChainExecution { public static void main(String[] args) { Handler1 handler1 = new Handler1(); Handler2 handler2 = new Handler2(); Handler3 handler3 = new Handler3(); Handler4 handler4 = new Handler4();
handler1.setNext(handler2); handler2.setNext(handler3); handler3.setNext(handler4);
handler1.handle(); }
|
小结:
- 责任链模式降低了系统之间的耦合性,提升了系统的可扩展性。
- 在很多中间件、框架的内部大量地使用了该种设计模式,比如Filter的执行过程等。

coo1heisenberg's Blog
Diligence can make up for clumsiness!