• Java设计模式很难吗,这篇带你熟悉设计模式


    3.1 概述

    可以发现,设计模式好像都是类似的。越看越感觉都着不多。其实都是类似面向接口编程的一种体现,只不过侧重点不一样或者说要体现的结果不一样。

    3.2 使用场景

    问题一:应对可能变化的对象实现

    方案:间接创建

    模式:工厂模式

    问题二:为请求指定相应的操作(类似请假审批,不同时长对应不同职位的审批人)

    方案:程序根据请求动态选择操作

    模式:责任链模式

    3.3 具体说明

    3.3.1 策略模式

    • 策略模式说明

    一个行为型模式,包含多个行为或职责的业务,通过策略模式简化

    1. public class StrategyContext {
    2. Strategy strategy;
    3. public StrategyContext(Strategy strategy) {
    4. this.strategy = strategy;
    5. }
    6. /**
    7. *
    8. */
    9. public int context(int a, int b) {
    10. return strategy.operator(a,b);
    11. }
    12. }

    策略模式的核心为StrategyContext上下文类,持有strategy对象,在context完成操作。

    • 策略模式实践

    如何使用策略模式解决大量使用if else 或大量switch问题,策略模式+反射。

    策略模式后好像使用都还是要用if else来决定调用哪个类,所以在引入策略模式后,在上下文类还要增加反射。

    1. public class StrategyContext {
    2. Strategy strategy;
    3. public StrategyContext(String type) throws Exception {
    4. Class clazz = Class.forName(type);
    5. this.strategy = (Strategy) clazz.newInstance();
    6. }
    7. /**
    8. *
    9. */
    10. public int context(int a, int b) {
    11. return strategy.operator(a,b);
    12. }

    当然这里的type可以用个枚举来解决。感觉代价非常大是不是没必要,不过代码的可读性还是增强了。

    p.s. 在框架里策略模式中的Context一般不会直接出现,类似spring中直接在使用时就通过注解给设置了

    3.3.2、装饰器模式

    描述:原接口Shape不变,方法数量不变,在方法实现中增加修饰

    场景:

    场景一:一个类功能简单,满足不了我们的需求

    场景二:给原方法增加日志功能,不改变原方法,新的实现类去实现此功能,带入的对象为接口对象

    特点

    • 原接口Shape不动,增加新的装饰类ShapeDecorator
    • 原方法名不变,只是增加或修饰此方法体
    • ColorShapeDecorator装饰类持有原对象,只是增加了修饰
    1. public class ColorShapeDecorator extends ShapeDecorator {
    2. public ColorShapeDecorator(Shape shape) {
    3. super(shape);
    4. }
    5. @Override
    6. public void draw() {
    7. setColor();
    8. shape.draw();
    9. }
    10. private void setColor() {
    11. //设置画图颜色
    12. }
    13. }

    3.3.3 代理模式

    设置一个中间代理来控制访问原目标对象,达到增强原对象的功能和简化访问方式的目的

    场景:

    场景一:不改变原方法,对原方法增加耗时的计算

    场景二:rpc远程调用,client端进行动态代理类似耗时计算一样,用户不用关心client的具体实现

    分类

    • 静态代理模式
    • 动态代理模式

    说明

    • 静态代理模式
    1. /**
    2. * 与适配器模式的区别,适配器模式主要改变所考虑对象的接口,
    3. * 而代理模式不能改变所代理类的接口。与装饰器模式的区别,
    4. * 装饰器模式是为了增强功能,代理模式是为了加以控制
    5. */
    6. public class ProxySigntureService implements SigntureService {
    7. private SigntureService signatureService;
    8. /**
    9. * Default constructor
    10. */
    11. public ProxySigntureService(SigntureService signatureService) {
    12. this.signatureService = signatureService;
    13. }
    14. public void sign() {
    15. //控制对这个对象的访问
    16. // 实现电子签名
    17. }
    18. }
    • 动态代理模式
    1. public class DynamicProxySignatureService implements InvocationHandler {
    2. private Object obj;
    3. public DynamicProxySignatureService(Object obj) {
    4. this.obj = obj;
    5. }
    6. @Override
    7. public Object invoke(Object proxyObj, Method method, Object[] objects)
    8. throws Throwable {
    9. return method.invoke(obj,objects);
    10. }
    11. }

    参考文章:https://blog.csdn.net/liujiahan629629/article/details/19428485

    3.3.4 适配器模式

    描述:原接口不变,增加方法数量

    场景:

    场景一:原接口不变,在基础上增加新的方法。

    场景二:接口的抽象方法很多,不想一一实现,使用适配器模式继承原实现类,再实现此接口

    • 适配器模式适合需要增加一个新接口的需求,在原接口与实现类基础上需要增加新的接口及方法。类似原接口只能method01方法,需求是增加method02方法,同时不再使用之前接口类。

    新接口

    1. public interface Targetable {
    2. /**
    3. *
    4. */
    5. public void method01();
    6. /**
    7. *
    8. */
    9. public void method02();
    10. }

    原接口实现类

    1. public class Source {
    2. public void method01() {
    3. // TODO implement here
    4. }
    5. }

    适配器类,用于实现新接口。继承原实现类,同时实现新接口。

    1. public class Adapter extends Source implements Targetable {
    2. /**
    3. *
    4. */
    5. public void method02() {
    6. // TODO implement here
    7. }
    8. }

    测试类

    1. public class AdapterTest {
    2. public static void main(String[] args) {
    3. Targetable targetable = new Adapter();
    4. targetable.method01();
    5. targetable.method02();
    6. }
    7. }

    3.3.5 单例模式

    保证被创建一次,节省系统开销。

    1)单例实现方式

    • 饿汉式
    • 懒汉式
    • 懒汉式+synchronized
    • 双重校验
    • 静态内部类
    • 枚举(推荐方式)

    2)实现代码

    • 饿汉式
    1. package com.hanko.designpattern.singleton;
    2. /**
    3. * 饿汉式 (饿怕了,担心没有吃,所以在使用之前就new出来)
    4. *优点:实现简单,安全可靠
    5. *缺点:在不需要时,就已实例化了
    6. * @author hanko
    7. * @version 1.0
    8. * @date 2020/9/14 18:50
    9. */
    10. public class HungrySingleton {
    11. //特点一 静态私有变量 直接初始化
    12. private static HungrySingleton instance = new HungrySingleton();
    13. //特点二 构造函数私有
    14. private HungrySingleton(){
    15. }
    16. public static HungrySingleton getInstance(){
    17. return instance;
    18. }
    19. public void doSomething(){
    20. //具体需要实现的功能
    21. }
    22. }
    • 懒汉式
    1. package com.hanko.designpattern.singleton;
    2. /**
    3. * 懒汉式(非常懒,所以在要使用时再去new)
    4. *优点:简单
    5. *缺点:存在线程安全问题
    6. * @author hanko
    7. * @version 1.0
    8. * @date 2020/9/14 18:50
    9. */
    10. public class SluggardSingleton {
    11. //特点一 静态私有变量,先不初始化
    12. private static SluggardSingleton instance;
    13. //特点二 构造函数私有
    14. private SluggardSingleton(){
    15. }
    16. //特点三 null判断,没有实例化就new
    17. public static SluggardSingleton getInstance(){
    18. if(instance == null){
    19. instance = new SluggardSingleton();
    20. }
    21. return instance;
    22. }
    23. public void doSomething(){
    24. //具体需要实现的功能
    25. }
    26. }
    • 懒汉式+Synchronized
    1. package com.hanko.designpattern.singleton;
    2. /**
    3. * 懒汉式(非常懒,所以在要使用时再去new)
    4. *优点:简单
    5. *缺点:存在线程安全问题
    6. * @author hanko
    7. * @version 1.0
    8. * @date 2020/9/14 18:50
    9. */
    10. public class SluggardSingleton {
    11. //特点一 静态私有变量,先不初始化
    12. private static SluggardSingleton instance;
    13. //特点二 构造函数私有
    14. private SluggardSingleton(){
    15. }
    16. //特点三 null判断,没有实例化就new
    17. public static synchronized SluggardSingleton getInstance(){
    18. if(instance == null){
    19. instance = new SluggardSingleton();
    20. }
    21. return instance;
    22. }
    23. public void doSomething(){
    24. //具体需要实现的功能
    25. }
    26. }
    • 双重校验
    1. package com.hanko.designpattern.singleton;
    2. /**
    3. * 双重校验
    4. *对懒汉式单例模式做了线程安全处理增加锁机制
    5. * volatile变量级
    6. * synchronized 类级
    7. * @author hanko
    8. * @version 1.0
    9. * @date 2020/9/15 9:53
    10. */
    11. public class DoubleCheckSingleton {
    12. //特点一 静态私有变量,增加volatile变量级锁
    13. private static volatile DoubleCheckSingleton instance;
    14. //特点二 构造函数私有
    15. private DoubleCheckSingleton(){
    16. }
    17. //特点三 双重null判断 synchronized类级锁
    18. public static DoubleCheckSingleton getInstance(){
    19. if (instance == null){
    20. synchronized(DoubleCheckSingleton.class){
    21. if (instance == null){
    22. instance = new DoubleCheckSingleton();
    23. }
    24. }
    25. }
    26. return instance;
    27. }
    28. }
    • 静态内部类
    1. package com.hanko.designpattern.singleton;
    2. /**
    3. * 内部静态类方式
    4. *优点:静态内部类不会在InnerStaticSingleton类加载时加载,
    5. * 而在调用getInstance()方法时才加载
    6. *缺点:存在反射攻击或者反序列化攻击
    7. * @author hanko
    8. * @version 1.0
    9. * @date 2020/9/15 10:03
    10. */
    11. public class InnerStaticSingleton {
    12. //特点一:构造函数私有
    13. private InnerStaticSingleton(){
    14. }
    15. //特点二:静态内部类
    16. private static class InnerSingleton{
    17. private static InnerSingleton instance = new InnerSingleton();
    18. }
    19. public InnerSingleton getInstance(){
    20. return InnerSingleton.instance;
    21. }
    22. public void doSomething(){
    23. //do Something
    24. }
    25. }
    • 枚举(推荐方式)
    1. package com.hanko.designpattern.singleton;
    2. /**
    3. * 枚举实现单例简单安全
    4. *
    5. * @author hanko
    6. * @version 1.0
    7. * @date 2020/9/14 19:01
    8. */
    9. public enum EnumSingleton {
    10. INS;
    11. private Singleton singleton;
    12. EnumSingleton() {
    13. singleton = new Singleton();
    14. }
    15. public void doSomething(){
    16. singleton...
    17. //具体需要实现的功能
    18. }
    19. }
    20. EnumSingleton.INS.doSomething();

    3.3.6 工厂模式

    (简单工厂、抽象工厂):解耦代码。

    简单工厂:用来生产同一等级结构中的任意产品,对于增加新的产品,无能为力。

    工厂方法:用来生产同一等级结构中的固定产品,支持增加任意产品。

    抽象工厂:用来生产不同产品族的全部产品,对于增加新的产品,无能为力;支持增加产品族。

    参考文章:几种常用的设计模式--工厂模式 - 知乎

    3.3.7 观察者模式

    定义了对象之间的一对多的依赖,这样一来,当一个对象改变时,它的所有的依赖者都会收到通知并自动更新。

    3.3.8 外观模式

    提供一个统一的接口,用来访问子系统中的一群接口,外观定义了一个高层的接口,让子系统更容易使用。

    3.3.9 状态模式

    允许对象在内部状态改变时改变它的行为,对象看起来好像修改了它的类。与策略模式类似,策略模式侧重点在一个事的不同实现方式抽离出来,而状态模式是一个事的不同状态抽离出来(开始、进行中、结束),每次状态完成自己的业务逻辑。

    3.4 总结:

    • 适配器模式(原功能不变,增加新功能)、装饰器模式(装饰原功能)、代理模式(控制原功能)
    • 策略模式侧重点在一个事的不同实现方式抽离出来,而状态模式是一个事的不同状态抽离出来(开始、进行中、结束),每次状态完成自己的业务逻辑。

  • 相关阅读:
    JVM学习----垃圾回收调优
    oracle停库迁移
    Day22_8 Java学习之反射、多线程
    工作游戏时mfc140u.dll丢失的解决方法,哪个方法可快速修复mfc140u.dll问题
    【论文精读】TextDiffuser-2:释放语言模型用于文本渲染的力量
    Vue开发中常见问题记录
    Tekla添加零件ContourPlate
    Elasticsearch-02-es的restapi使用
    米家、涂鸦、Hilink、智汀等生态哪家强?5大主流智能品牌分析
    无代码编程时代的到来:新兴工具和平台的前瞻展望
  • 原文地址:https://blog.csdn.net/citywu123/article/details/127987892