第三周课程总结
设计模式
什么是设计模式?
每一种设计模式都描述了一种问题的通用解决方案。这种问题在我们的环境中,不停地的出现
设计模式是一种可重复使用的解决方案。
设计模式的组成
模式的名称 - 少量的字组成的名称
待解决问题 - 描述了何时需要运用这种模式,以及运用模式的环境
解决方案 - 描述了组成设计的元素(类和对象),它们的关系、职责以及合作。但这种解决方案是抽象的,它不代表具体实现
结论 - 运用这种方案所带来的利弊。主要是指它对系统的弹性、扩展性、可移植性
如何创建一个对象?(工厂模式)
需求(V1):程序需要根据文件的后缀名,选择不同的解析类进行文件解析。解析的内容是User信息。
实现:
如果增加了一个用户配置解析类(PropertiesUserConfigReader),那么就需要改变choose UserConfigReader块逻辑。
会产生如下问题:
定位代码(不知道choose UserConfigReader代码逻辑在哪,按照正常思路来讲,choose UserConfigReader 不应该掺杂在业务代码中)
choose UserConfigReader 代码复用问题
存在的问题:UserConfigReader的创建逻辑的无扩展性不好,UserConfigReader创建代码无法复用。
解决方案 V1
以上代码解决了哪些问题?
代码复用问题(将choose逻辑统一封装在UserConfigReaderFactory中)
我们如果需要添加PropertiesUserConfigReader,可以直接定位到UserConfigReaderFactory类中,进行逻辑修改。但并不符合OCP原则。
存在的问题:以上无法满足OCP原则
解决方案 V2
以上代码解决了哪些问题:
基本满足OCP原则
解决方案V1 VS 解决方案V2
解决方案V1
优点:
调用工厂方法获取的对象,每次都是新创建的,支持不可重复使用的对象。
if else分支少时,可读性较好。
缺点:
扩展时,不满足OCP原则。
if else分支很多时,可读性较差。
调用方法获取对象,每次都是新创建对象,浪费内存,性能相对于解决方案V2较差。
如果工厂生成的对象在创建时,过程十分复杂,会导致工厂方法非常混乱。
解决方案V2
优点:
调用工厂方法获取的对象,每次都是获取Map中的缓存对象,避免对象重复创建的消耗,节约内 存。相对于解决方案V1性能较好。
基本满足OCP原则(如果需要注册其他UserConfigReader,在运行期直接调用registryUserConfigReader方法注册对应的UserConfigReader即可)。
缺点:
不支持不可重复使用的对象。
如果工厂生成的对象在创建时,过程十分复杂,会导致工厂方法非常混乱。
解决方案V2.1(配置文件)
优点 相比于 解决方案V2:
配置文件更加灵活
缺点
增加功能复杂度
存在的问题:如果工厂生成的对象在创建时,过程十分复杂,会导致工厂方法非常混乱。
例如:
创建JsonUserConfigReader、XmlUserConfigReader实例时,需要较复杂的初始化方法,使用以上方法就并不理想了。
需要使用工厂方法模式来解决该问题。
工厂方法模式隔离了复杂了初始化操作,如果这些初始化都挤在一个方法里可读性会很差。
如何使用工厂方法模式呢?直接new吗?
一般来讲使用简单工厂模式生成工厂方法模式的工厂。
工厂模式总结
解决方案V1很明显违反了OCP原则,那它就不会被使用吗?
考虑到当前所面对的场景还是很重要的!如果当前类逻辑并不是特别复杂,if分支并不是很多,可以接受这种方式。
很多优秀的开源框架也在使用这种方式
来源于Netty4
来源于JDK
工厂模式的本质:隔离复杂的对象创建逻辑,将对象创建逻辑委派给对象工厂来进行创建。
对象创建一次就够了!(单例设计模式)
单例设计模式本质:避免浪费内存,减轻GC压力,一个对象只创建一次。
单例模式 饿汉式
单例模式 懒汉式
单例模式懒汉式 加强版 DCL
饿汉式
优点:
简单易懂
缺点:
在这个类还不需要时,就已经被创建了,也就是说在这个类被加载到虚拟机的时候这个单例就被创建了
懒汉式
优点:
按需创建
相比于加强版饿汉式 简单易懂
缺点:
多线程访问每次都需要获取锁,效率低下,加强版饿汉式只需要在第一次访问创建对象时会竞争锁。
商品一会儿一个价格怎么办?(策略模式)
需求:商品在上午9-11点时打9折,11点至18点时打8折,其余时间不打折。
如果打折策略再增加,比如说周末,以及端午等打折策略。
这是一个比较易变的需求,营销也会经常组织打折活动。
策略模式本质:抽象出一个接口用于描述算法,这个算法会有多种实现。
组合优于继承!(装饰器模式)
InputStream是对一个输入流的抽象
需求:
对InputStream进行增强,需要提供InputStream read缓冲区,InputStream read只可以读取byte,还需要提供可以readInt,readLong功能。
反例:
现在又提出需求,既要支持readInt又要提供缓冲区,我们可能还会来一个BufferedDataInputStream,这只是两个功能,就需要创建三个类。基础功能的类,与排列组合来的类,这样类会爆炸。
装饰模式优化
这样如果它们需要排列组合
优点:
相比于继承 不会像继承那样因功能排列组合导致更多的类。
装饰器模式本质:在原有类的基础上,增强原有功能。
与代理模式、AOP的区别,代理模式、AOP适合做与本身类功能无关的功能,例如记日志、拦截器权限控制等。
评论