7.设计模式阶段总结

设计模式总结

回顾软件设计原则

设计模式简介

设计原则 解释
开闭原则 对扩展开放,对修改关闭。
依赖倒置原则 通过抽象使各个类或者模块不相互影响,实现松耦合。
单一职责原则(6大原则不包括他) 一个类、接口、方法只做一件事。
接口隔离原则 尽量保证接口的纯洁性,客户端不应该依赖不需要的接口。
迪米特法则 又叫最少知道原则,一个类对其所依赖的类知道得越少越好。
里氏替换原则 子类可以扩展父类的功能但不能改变父类原有的功能。
合成复用原则 尽量使用对象组合、聚合,而不使用继承关系达到代码复用的目的。

经典框架都在用设计模式解决问题

设计模式名称 举例
工厂模式 BeanFactory
装饰器模式 BeanWrapper
代理模式 AopProxy
委派模式 DispatcherServlet
策略模式 HandlerMapping
适配器模式 HandlerAdapter
模板模式 JdbcTemplate
观察者模式 ContextLoaderListener

设计模式

类型 名称 英文
创建型模式 工厂模式 Factory Pattern
创建型模式 单例模式 Singleton Pattern
创建型模式 原型模式 Prototype Pattern
结构型模式 适配器模式 Adapter Pattern
结构型模式 装饰器模式 Decorator Pattern
结构型模式 代理模式 Proxy Pattern
行为性模式 策略模式 Strategy Pattern
行为性模式 模板模式 Template Pattern
行为性模式 委派模式 Delegate Pattern
行为性模式 观察者模式 Observer Pattern

工厂模式

简单工厂

  • 简单工厂模式(Simple Factory Pattern)
    • 课程为例,课程为例 有java课程 ,有python课程等,课程Factory 创建课程,调用课程方法
    • jdk Calendar.getInstance()
  • 工厂方法模式(Fatory Method Pattern)
    • 课程为例 不同课程有不同职责(单一职责) ,java课程有javaFactory去创建,python课程有python Factory创建
    • logback
  • 抽象工厂模式(Abastract Factory Pattern)
    • 以课程为例,课程添加了职责(多个职责),课程工厂提供多个职责,java 产品线不同人做不同事,python 产品线不同人做不同事,

单例模式(Singleton Pattern)

饿汉式单例

  • 饿汉式单例是在类加载的时候就立即初始化,并且创建单例对象。绝对线程安全,在线 程还没出现以前就是实例化了,不可能存在访问安全问题

懒汉式单例

  • 被外部类调用的时候内部类才会加载 (线程不安全)
    • synchronized
      • 单锁 线程阻塞,效率不高
      • 双重锁 指令重排 volatile
      • 静态内部类
  • 反射破坏单例
    //史上最牛 B 的单例模式的实现方式 
    public class LazyInnerClassSingleton { 
        //默认使用 LazyInnerClassGeneral 的时候,会先初始化内部类 
        // 如果没使用的话,内部类是不加载的 
        //TODO 防止反射破坏单例
        private LazyInnerClassSingleton() {
            if (LazyHolder.LAZY != null) {
                throw new RuntimeException("不允许创建多个实例");
            }
        }
        //每一个关键字都不是多余的 
        // static 是为了使单例的空间共享 
        // 保证这个方法不会被重写,重载 
         public static final LazyInnerClassSingleton getInstance(){ 
            //在返回结果以前,一定会先加载内部类 
             return LazyHolder.LAZY; 
             
        }
        //默认不加载 
        private static class LazyHolder{ 
            private static final LazyInnerClassSingleton LAZY = new LazyInnerClassSingleton(); 
        }

    }
  • 序列化破坏单例
    • readResolve() 方法

注册式单例

  • 枚举登记
  • 容器缓存

ThreadLocal 线程单例

  • ThreadLocal 不能保证其 创建的对象是全局唯一,但是能保证在单个线程中是唯一的,天生的线程安全

原型模式

简单克隆

  • 只是完整 复制了值类型数据,没有赋值引用对象

深度克隆

  • 引用的对象也克隆了
    • 引用对象也clone() ;
      • 缺点:使用Clone方法实现深复制存在的缺点: 存在多个引用的成员变量,将做多次处理。
    • 序列化/反序列化,代码如下:
     public Object deepCopy() throws Exception {
        //将对象写入流
        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        ObjectOutputStream oos = new ObjectOutputStream(bos);
        oos.writeObject(this);
        //从流中读取对象
        ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
        ObjectInputStream ois = new ObjectInputStream(bis);
        return ois.readObject();
    }
    1)在Java语言里深克隆一个对象,常常可以先使对象实现Serializable接口,然后把对象(实际上只是对象的一个拷贝)写到一个流里,再从流里读出来,便可以重建对象。
    2)这样做的前提示对象以及对象内部所有引用到的对象都是可串行化的,否则,就需要仔细考察那些不可串行化的对象是否设成transient,从而将之排除在复制过程之外。
    
    //TODO 
    六、关于实现Seriallizable接口的类中的serialVersionUID问题
    
    如果你的对象序列化后存在硬盘上面后,可是后来你更改了类的field(增加或减少或改名),当你反序列化时,就会出现Execption的,这样就会造成不兼容性的问题。
    
    但当serialVersionUID相同时,它就会将不一样的field以type的缺省值Deserialize,这样可以避开不兼容的问题。
    

克隆破坏单例

  • 要么你我们的单例类不实现 Cloneable 接口;要么我们重写 clone()方法,在 clone 方法中返回单例对象即可,具体 代码如下:
@Override 
protected Object clone() throws CloneNotSupportedException { 
    return INSTANCE;
}

代理模式

静态代理

  • 王爸给小王相亲, 相亲过程中,王爸就是小王的代理(类王爸中有小王类[ 有个相亲方法],王爸类中有方法去调用成员变量小王类的相亲方法)
  • 业务举例,订单业务扩容,分库分表, 创建数据库路由类(数据源等),静态代理类, StaticProxy( ? implements InterFace)

动态代理

jdk代理

  • 反射获取

CGLib代理

  • FastClass 机 制
  • FastClass 并不是跟代理类一块生成的,而是在第一次执行 MethodProxy -->invoke/invokeSuper 时生成的并放在了缓存中

CGLib 和 JDK 动态代理对比

  1. JDK 动态代理是实现了被代理对象的==接口==,CGLib 是继承了被代理对象。
  2. JDK 和 CGLib 都是在运行期生成字节码,JDK 是直接写 Class 字节码,CGLib 使用 ASM 框架写 Class 字节码,Cglib 代理实现更复杂,生成代理类比 JDK 效率低。
  3. JDK 调用代理方法,是通过反射机制调用,CGLib 是通过 FastClass 机制直接调用方法, CGLib 执行效率更高。

委派模式

  • 老板(Boss)给项目经理(Leader)下达任务,项目经理会根据 实际情况给每个员工派发工作任务,待员工把工作任务完成之后,再由项目经理汇报工 作进度和结果给老板

策略模式

  • 极客时间打折 ①.满减 ②.新课邀请减③ 拼团
  • 美团外卖选择支付方式 ①.美团支付 ②.支付宝支付③ 微信支付 ④银联支付等等

模板模式

  • 入职流程:填写入职登记表-->打印简历-->复印学历-->复印身份证-->签订 劳动合同-->建立花名册-->办理工牌-->安排工位等
  • 炒菜:洗锅 -->点火-->热锅-->上油-->下原料-->翻炒-->放调料-->出锅

适配器模式

  • xx网站登录 ①.注册登录 ②. 微信.③ 手机号 等等
public class LoginForWechatAdapter implements LoginAdapter {
    public boolean support(Object adapter) { 
        return adapter instanceof LoginForWechatAdapter; 
        
    }
    public ResultMsg login(String id, Object adapter) { 
        sout(  WechatAdapter 登录  ... );
    } 
}

装饰者模式

  • 如给煎饼加鸡蛋;给蛋糕加上一些水果;给房子 装修等

观察者模式

  • 微信通知 Observer\Observable Event com.google.guava @Subscribe

单例模式和工厂模式

  • 实际业务代码中,通常会把工厂类设计为单例

策略模式和工厂模式

  1. 工厂模式包含工厂方法模式和抽象工厂模式是创建型模式,策略模式属于行为型模 式。
  2. 工厂模式主要目的是封装好创建逻辑,策略模式接收工厂创建好的对象,从而实现不 同的行为。

策略模式和委派模式

  1. 策略模式是委派模式内部的一种实现形式,策略模式关注的结果是否能相互替代。
  2. 委派模式更关注分发和调度的过程。

模版方法和工厂方法模式

  1. 模板方法和策略模式都有封装算法。
  2. 策略模式是使不同算法可以相互替换,且不影响客户端应用层的使用。
  3. 模板方法是针对定义一个算法的流程,将一些有细微差异的部分交给子类实现。
  4. 模板方法模式不能改变算法流程,策略模式可以改变算法流程且可替换。策略模式通 常用来代替 if...else...等条件分支语句

模版方法和策略模式

  1. 装饰者模式关注点在于给对象动态添加方法,而代理更加注重控制对对象的访问。
  2. 代理模式通常会在代理类中创建被代理对象的实例,而装饰者模式通常把被装饰者作 为构造参数。

装饰者模式和静态代理模式

  1. 装饰者模式和适配器模式都是属于包装器模式(Wrapper Pattern)。
  2. 装饰者模式可以实现被装饰者与相同的接口或者继承被装饰者作为它的子类,而适配 器和被适配者可以实现不同的接口。

spring aop Execution 表达式

  • execution(modifiers-pattern? ret-type-pattern declaring-type-pattern? name-pattern(param-pattern) throws-pattern?)
modifiers-pattern:方法的操作权限
ret-type-pattern:返回值【必填】
declaring-type-pattern:方法所在的包
name-pattern:方法名 【必填】
parm-pattern:参数名 
throws-pattern:异常
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容