架构第三周 - 学习总结
这周主要的学习内容就是关于设计模式、设计原则、重构
心得体会
除了课堂内的内容,还有些比较重要的题外话我想先拿出来讲一下。
找出问题的人比解决问题的人高出一个Level。好比发现设计问题比去用这些设计模式更NB一点。
阅读源码最好是好奇心驱动、工作驱动。
其实我在找工作的之前或者过程中做了这部分补充,比如我阅读了spring的源码,串联了知识体系,理解了IOC、AOP的设计源码和原理。源码之下无秘密,所言不虚!
忽略不必要的细节以节省精力专注于更加重要的事情上。当然这个也是因人而异。
SOLID设计原则
单一职责原则(S)
开闭原则(O)
里式替换原则(L):与多态思想不同,是一种指导子类设计的设计原则,子类的设计要保证在替换父类的时候,不改变原有程序的逻辑以及不破坏原有程序的正确性。
接口隔离原则(I):客户端不应该被强迫依赖它不需要的接口。
依赖倒置原则(D):高层模块不要依赖底层模块,抽象不要依赖具体。
其他还有:KISS原则(Keep It Simple and Stupid) DRY原则、YAGNI原则、迪米特法则(有限知识原则、不要和陌生人说话)
设计模式
策略模式
策略的定义
策略类的定义比较简单,包含一个策略接口和一组实现这个接口的策略类。
因为所有的策略类都实现相同的接口。所以,客户端代码基于接口而非实现编程,可以灵活地替换不同的策略!
策略的创建
因为策略模式会包含一组策略,在使用它们的时候,一般会通过类型(type)来判断创建哪个策略来使用。
为了封装创建逻辑,我们需要对客户端代码屏蔽创建细节。我们可以把根据 type 创建策略的逻辑抽离出来,放到工厂类中。
本质上都是借助“查表法”,根据 type 查表(代码中的 strategies 就是表)替代根据 type 分支判断。
无状态策略
这样的策略对象是可以被共享使用的,不需要在每次调用 getStrategy() 的时候,都创建一个新的策略对象。
这个工厂代码存放的一般是无状态策略。
有状态策略
如果策略类是有状态的,根据业务场景的需要,我们希望每次从工厂方法中,获得的都是新创建的策略对象,而不是缓存好可共享的策略对象,那我们就需要按照如下方式来实现策略工厂类!
单例模式的几种方式
饿汉式
在类加载的时候静态实例就已经初始化好了,线程安全。
懒汉式
延迟加载初始化,一把大锁,线程安全。
双重检测
原型模式
原型模式:其实就是从一个对象再创建另外一个可定制的对象,而不需要知道任何的创建细节。
分为浅层复制和深层复制。
java的clone()方法默认为浅层复制。引用类型只会复制指针但是不会复制数据。
深层复制的实现方式:
工厂模式
简单工厂模式+工厂方法模式
简单工厂模式
直接在条件判断中根据不同参数将目标对象new了出来。
工厂方法模式
是将目标对象的创建过程根据参数分别抽取到各自独立的工厂类中,以应对目标对象创建过程的复杂度。条件分支可以使用map来缓存起来!
案例:java.util.Calendar的getInstance() 方法可以根据不同 TimeZone 和 Locale,创建不同的 Calendar 子类对象。也是用到建造者模式。
建造者模式
通过内部的Builder类主导目标对象的创建同时校验必选属性之间的依赖关系。如下set方法中包含一些校验,然后再build()中统一校验。
装饰器模式
装饰器模式把每个要装饰的功能放到单独的类中,并让这个类包装它所需要装饰的对象,从而实现对原始类的增强。
代理模式与装饰器模式的区别:
装饰器模式中,装饰器类附加的是跟原始类相关的增强功能。
代理模式中,代理类附加的是跟原始类无关的功能
案例:java的IO类库比如InputStream和BufferInputStream。还有Collections类。
职责链模式
在职责链模式中,多个处理器依次处理同一个请求。
一个请求先经过 A 处理器处理,然后再把请求传递给 B 处理器,B 处理器处理完后再传递给 C 处理器,以此类推,形成一个链条。链条上的每个处理器各自承担各自的处理职责,所以叫作职责链模式。
在 GoF 给出的定义中,如果处理器链上的某个处理器能够处理这个请求,那就不会继续往下传递请求(下面代码所示)。实际上,职责链模式还有一种变体,那就是请求会被所有的处理器都处理一遍,不存在中途终止的情况。
职责链模式有两种常用的实现。一种是使用链表来存储处理器,另一种是使用数组来存储处理器,后面一种实现方式更加简单。
应用场景:Servlet中的Filter、Netty的ChannelPipeline.
代理模式
静态代理
jdk动态代理:被代理类需要实现接口
cglib动态代理:不需要实现接口
如果被代理类被标记成final,也就无法通过CGLIB去创建动态代理:
java.lang.IllegalArgumentException: Cannot subclass final class class spring.PersonServiceImpl
如果被代理方法被标记为final,也无法正常实现代理功能
SpringAOP的实现:
如果目标对象实现了接口,默认采用JDK动态代理。
如果没有实现接口则采用CGLIB动态代理。
模板方法模式
由父类实现通用逻辑,具体细节留给子类去实现。减少代码重复度!
适配器模式
这个模式就是用来做适配的,它将不兼容的接口转换为可兼容的接口,让原本由于接口不兼容而不能一起工作的类可以一起工作。
适配器模式有两种实现方式:类适配器和对象适配器。其中,类适配器使用继承关系来实现,对象适配器使用组合关系来实现
代码实现:
其中,ITarget 表示要转化成的接口定义。Adaptee 是一组不兼容 ITarget 接口定义的接口,Adaptor 将 Adaptee 转化成一组符合 ITarget 接口定义的接口
类适配器: 基于继承
对象适配器:基于组合
如何选择?
如果 Adaptee 接口并不多,那两种实现方式都可以!
如果 Adaptee 接口很多呢?
Adaptee 和 ITarget 接口定义大部分都相同,推荐使用类适配器,因为可以让 Adaptor 复用父类 Adaptee 的接口。
Adaptee 和 ITarget 接口定义大部分都不相同,推荐使用对象适配器,因为组合结构相对于继承更加灵活!
SpringMVC中适配器模式
针对Servlet、Controller、注解的Handler组件适配为HandlerAdapter,统一调用handle(...)方法进行逻辑处理,省去了handler具体实现类的判断。
版权声明: 本文为 InfoQ 作者【J.Spring】的原创文章。
原文链接:【http://xie.infoq.cn/article/94a3ea8981fe892644a6a4c16】。文章转载请联系作者。
评论