3.1 概述
可以发现,设计模式好像都是类似的。越看越感觉都着不多。其实都是类似面向接口编程的一种体现,只不过侧重点不一样或者说要体现的结果不一样。
3.2 使用场景
问题一:应对可能变化的对象实现
方案:间接创建
模式:工厂模式
问题二:为请求指定相应的操作(类似请假审批,不同时长对应不同职位的审批人)
方案:程序根据请求动态选择操作
模式: 责任链模式
3.3 具体说明
3.3.1 策略模式
- 策略模式说明
一个行为型模式,包含多个行为或职责的业务,通过策略模式简化
public class StrategyContext { | |
Strategy strategy; | |
public StrategyContext(Strategy strategy) { | |
this.strategy = strategy; | |
} | |
/** | |
* | |
*/ public int context(int a, int b) { | |
return strategy.operator(a,b); | |
} | |
} |
策略模式的核心为StrategyContext上下文类,持有strategy对象,在context完成操作。
- 策略模式实践
如何使用策略模式解决大量使用 if else 或大量switch问题,策略模式+反射。
策略模式后好像使用都还是要用if else来决定调用哪个类,所以在引入策略模式后,在上下文类还要增加反射。
public class StrategyContext { | |
Strategy strategy; | |
public StrategyContext(String type) throws Exception { | |
Class clazz = Class.forName(type); | |
this.strategy = (Strategy) clazz.newInstance(); | |
} | |
/** | |
* | |
*/ public int context(int a, int b) { | |
return strategy.operator(a,b); | |
} |
当然这里的type可以用个枚举来解决。感觉代价非常大是不是没必要,不过代码的可读性还是增强了。
p.s. 在框架里策略模式中的Context一般不会直接出现,类似 spring 中直接在使用时就通过注解给设置了
3.3.2、装饰器模式
描述:原接口Shape不变,方法数量不变,在 方法实现中 增加修饰
场景:
场景一:一个类功能简单,满足不了我们的需求
场景二:给原方法增加日志功能,不改变原方法,新的实现类去实现此功能,带入的对象为接口对象
特点
- 原接口Shape不动,增加新的装饰类ShapeDecorator
- 原方法名不变,只是增加或修饰此方法体
- ColorShapeDecorator装饰类持有原对象,只是增加了修饰
public class ColorShapeDecorator extends ShapeDecorator { | |
public ColorShapeDecorator(Shape shape) { | |
super(shape); | |
} | |
public void draw() { | |
setColor (); | |
shape.draw(); | |
} | |
private void setColor() { | |
//设置画图颜色 | |
} | |
} |
3.3.3 代理模式
设置一个中间代理来控制访问原目标对象,达到 增强 原对象的功能和 简化 访问方式的目的
场景:
场景一:不改变原方法,对原方法增加耗时的计算
场景二: rpc 远程调用,client端进行动态代理类似耗时计算一样,用户不用关心 client 的具体实现
分类
- 静态代理模式
- 动态代理模式
说明
- 静态代理模式
/** | |
* 与适配器模式的区别, 适配器 模式主要改变所考虑对象的接口, | |
* 而代理模式不能改变所代理类的接口。与装饰器模式的区别, | |
* 装饰器模式是为了增强功能, 代理模式 是为了加以控制 | |
*/public class ProxySigntureService implements SigntureService { | |
private SigntureService signatureService; | |
/** | |
* Default constructor | |
*/ public ProxySigntureService(SigntureService signatureService) { | |
this.signatureService = signatureService; | |
} | |
public void sign() { | |
//控制对这个对象的访问 | |
// 实现电子签名 | |
} | |
} |
- 动态代理模式
public class DynamicProxySignatureService implements InvocationHandler { | |
private Object obj; | |
public DynamicProxySignatureService(Object obj) { | |
this.obj = obj; | |
} | |
public Object invoke(Object proxyObj, Method method, Object[] objects) | |
throws Throwable { | |
return method.invoke(obj,objects); | |
} | |
} |
参考文章:
3.3.4 适配器模式
描述: 原接口不变,增加 方法数量
场景:
场景一:原接口不变,在基础上增加新的方法。
场景二:接口的抽象方法很多,不想一一实现,使用适配器模式继承原实现类,再实现此接口
- 适配器模式适合需要 增加一个新接口的需求 ,在原接口与实现类基础上需要增加新的接口及方法。类似原接口只能method01方法,需求是增加method02方法,同时不再使用之前接口类。
新接口
public interface Targetable { | |
/** | |
* | |
*/ public void method(); | |
/** | |
* | |
*/ public void method(); | |
} |
原接口实现类
public class Source { | |
public void method() { | |
// TODO implement here | |
} | |
} |
适配器类,用于实现新接口。继承原实现类,同时实现新接口。
public class Adapter extends Source implements Targetable { | |
/** | |
* | |
*/ public void method() { | |
// TODO implement here | |
} | |
} |
测试类
public class AdapterTest { | |
public static void main(String[] args) { | |
Targetable targetable = new Adapter(); | |
targetable.method(); | |
targetable.method(); | |
} | |
} |
3.3.5 单例模式
保证被创建一次,节省系统开销。
1)单例实现方式
- 饿汉式
- 懒汉式
- 懒汉式+ synchronized
- 双重校验
- 静态内部类
- 枚举(推荐方式)
2)实现代码
- 饿汉式
package com.hanko.designpattern.singleton; | |
/** | |
* 饿汉式 (饿怕了,担心没有吃,所以在使用之前就new出来) | |
*优点:实现简单,安全可靠 | |
*缺点:在不需要时,就已实例化了 | |
* @author hanko | |
* @version.0 | |
* @date/9/14 18:50 | |
*/public class HungrySingleton { | |
//特点一 静态私有变量 直接初始化 | |
private static HungrySingleton instance = new HungrySingleton(); | |
//特点二 构造函数私有 | |
private HungrySingleton(){ | |
} | |
public static HungrySingleton getInstance (){ | |
return instance; | |
} | |
public void doSomething(){ | |
//具体需要实现的功能 | |
} | |
} |
- 懒汉式
package com.hanko.designpattern.singleton; | |
/** | |
* 懒汉式(非常懒,所以在要使用时再去new) | |
*优点:简单 | |
*缺点:存在线程安全问题 | |
* @author hanko | |
* @version.0 | |
* @date/9/14 18:50 | |
*/public class SluggardSingleton { | |
//特点一 静态私有变量,先不初始化 | |
private static SluggardSingleton instance; | |
//特点二 构造函数私有 | |
private SluggardSingleton(){ | |
} | |
//特点三 null判断,没有实例化就new | |
public static SluggardSingleton getInstance(){ | |
if(instance == null){ | |
instance = new SluggardSingleton(); | |
} | |
return instance; | |
} | |
public void doSomething(){ | |
//具体需要实现的功能 | |
} | |
} |
- 懒汉式+Synchronized
package com.hanko.designpattern.singleton; | |
/** | |
* 懒汉式(非常懒,所以在要使用时再去new) | |
*优点:简单 | |
*缺点:存在线程安全问题 | |
* @author hanko | |
* @version.0 | |
* @date/9/14 18:50 | |
*/public class SluggardSingleton { | |
//特点一 静态私有变量,先不初始化 | |
private static SluggardSingleton instance; | |
//特点二 构造函数私有 | |
private SluggardSingleton(){ | |
} | |
//特点三 null判断,没有实例化就new | |
public static synchronized SluggardSingleton getInstance(){ | |
if(instance == null){ | |
instance = new SluggardSingleton(); | |
} | |
return instance; | |
} | |
public void doSomething(){ | |
//具体需要实现的功能 | |
} | |
} |
- 双重校验
package com.hanko.designpattern.singleton; | |
/** | |
* 双重校验 | |
*对懒汉式单例模式做了线程安全处理增加锁机制 | |
* volatile变量级 | |
* synchronized 类级 | |
* @author hanko | |
* @version.0 | |
* @date/9/15 9:53 | |
*/public class DoubleCheckSingleton { | |
//特点一 静态私有变量,增加 volatile 变量级锁 | |
private static volatile DoubleCheckSingleton instance; | |
//特点二 构造函数私有 | |
private DoubleCheckSingleton(){ | |
} | |
//特点三 双重null判断 synchronized类级锁 | |
public static DoubleCheckSingleton getInstance(){ | |
if (instance == null){ | |
synchronized(DoubleCheckSingleton.class){ | |
if (instance == null){ | |
instance = new DoubleCheckSingleton(); | |
} | |
} | |
} | |
return instance; | |
} | |
} |
- 静态内部类
package com.hanko.designpattern.singleton; | |
/** | |
* 内部静态类方式 | |
*优点:静态内部类不会在InnerStaticSingleton类加载时加载, | |
* 而在调用getInstance()方法时才加载 | |
*缺点:存在反射攻击或者反序列化攻击 | |
* @author hanko | |
* @version.0 | |
* @date/9/15 10:03 | |
*/public class InnerStaticSingleton { | |
//特点一:构造函数私有 | |
private InnerStaticSingleton(){ | |
} | |
//特点二:静态内部类 | |
private static class InnerSingleton{ | |
private static InnerSingleton instance = new InnerSingleton(); | |
} | |
public InnerSingleton getInstance(){ | |
return InnerSingleton.instance; | |
} | |
public void doSomething(){ | |
//do Something | |
} | |
} |
- 枚举(推荐方式)
package com.hanko.designpattern.singleton; | |
/** | |
* 枚举实现单例简单安全 | |
* | |
* @author hanko | |
* @version.0 | |
* @date/9/14 19:01 | |
*/public enum EnumSingleton { | |
INS; | |
private Singleton singleton; | |
EnumSingleton() { | |
singleton = new Singleton(); | |
} | |
public void doSomething(){ | |
singleton... | |
//具体需要实现的功能 | |
} | |
} | |
EnumSingleton.INS.doSomething(); |
3.3.6 工厂模式
(简单工厂、抽象工厂): 解耦 代码。
简单工厂:用来生产同一等级结构中的任意产品,对于增加新的产品,无能为力。
工厂方法:用来生产同一等级结构中的固定产品,支持增加任意产品。
抽象工厂:用来生产不同产品族的全部产品,对于增加新的产品,无能为力;支持增加产品族。
参考文章:
3.3.7 观察者模式
定义了对象之间的一对多的依赖,这样一来,当一个对象改变时,它的所有的依赖者都会收到通知并自动更新。
3.3.8 外观模式
提供一个统一的接口,用来访问子系统中的一群接口,外观定义了一个高层的接口,让子系统更容易使用。
3.3.9 状态模式
允许对象在内部状态改变时改变它的行为,对象看起来好像修改了它的类。与策略模式类似,策略模式侧重点在一个事的不同实现方式抽离出来,而状态模式是一个事的不同状态抽离出来(开始、进行中、结束),每次状态完成自己的业务逻辑。
3.4 总结:
- 适配器模式(原功能不变,增加新功能)、装饰器模式(装饰原功能)、代理模式(控制原功能)
- 策略模式侧重点在一个事的不同实现方式抽离出来,而状态模式是一个事的不同状态抽离出来(开始、进行中、结束),每次状态完成自己的业务逻辑。