–2017年12月14日
所谓设计模式,是大牛门总结的一种解题思路,是一种方法论,俗称套路
另外画UML图对理清设计模式特别有用,而弄明白设计模式对看各种源码特别有用
–20171215 没有那种设计模式是万能的 总会有缺点 特别是随着需求的复杂度提升而带来的不可避免的难度提升,所以我们只能找到最适合的 代码太多了 后续传项目附件吧 这里就只记录总结了
–偶然看到@水谷写的比较详细 类图也上了https://www.cnblogs.com/shuigu/p/6911822.html
面向对象的设计原则
为了方便拓展而设计的总则
说三点比较常见的原则:
单一职责:功能单一
开闭原则:对源码的更改关闭,对拓展开放
优先关联次继承:继承会造成父类的更改时必须更改全部子类,所以优先选用关联关系设计模式的分类
设计模式是在设计原则的基础上,在某些特定场景下而总结的解决方案
a.创造对象 –>创造型
b.对象或类之间的组合 –>结构型
c.对象或类之间的职责分配已经交互 –>行为型四人帮GOF N年前定义了23种设计模式,实际常用的也就哪些种 不常用的就不研究了
创造型模式
3.1.单例模式singletonPattern:只有一个实例
who:最常见最简单的一种,即只有一个实例
why:不用反复创建对象/销毁对象,节省这部分时间空间花销
how:禁止构造实例--private 构造方法()
提供获取唯一实例的方法-- public Myclass getInstance()
write:
where:资源方面的工具类Calendar.getInstance,spring的IOC里的bean实例(算是广义上的单例,new一个对象放在IOC中 然后一直只用这一个对象)
question:单例类通过反射可以创建新的实例吗?–无参构造方法private了
Class<?> clazz = Class.forName("com.pafa.wenching.learn.designPattern.singletonPattern.SingletonLazy");
Constructor<?> declaredConstructor2 = clazz.getDeclaredConstructor(null);
declaredConstructor.setAccessible(true);
Object newInstance = declaredConstructor.newInstance("xxx");
很遗憾 反射很强大 私有的构造方法也逃不过反射
question:单例类和静态方法
在一些工具类中,静态方法可以替代单例类,
1.从设计思想上说单例类更符合面向对象思想,因为使用的是对象,
2.静态方法过多可能造成方法区溢出
question:拓展成创建固定数量实例的类
在现有单例中,int maxNum,List<MyClass> instances,new的时候条件改变下,getInstance从集合里面取
question:单例类能被继承吗 –>一般不能,Eclipse直接编译不过
3.2.简单工厂-工厂方法-抽象工厂模式(FactoryPattern):创造大量对象,因需求复杂度或者维度而逐渐升级
who:对象工厂 故名思议 创建大量对象的工厂
why:为使用者提供创建对象的便利性,省去对象创建的过程
how:
1.简单工厂 如果只有简单的固定的产品需要创建,直接用if else判断并创建即可,但拓展新增产品时就需要改工厂源代码了,违反开闭原则
2.工厂方法 如果产品较多并且为了方便拓展时不违法开闭,就需要由简单工厂升级成工厂方法模式,
3.抽象工厂 工厂方法模式一个工厂只能产生一个产品,如果一个产品再细分成产品族,那就需要抽象工厂,
write:
where:sqlSessionFactory/BeanFactory
ps:每个子类单一职责的生产一种对象 一个多产品类的项目 会多出很多工厂子类 这种浪费和复杂度是由需求的复杂度提示而不可避免的带来的
public Human getHuman();-- 工厂 人分男女 男女工厂分别生产男女
-- 抽象工厂 人分男女 男女又分别分黑白黄种人
public HumanB getHumanB();//获的黑人 --再由男女工厂实现这三个方法 获取实例对象
public HumanY getHumanY();//获得黄种人
public HumanW getHumanW();//获得白种人
3.3.建造者模式(BuliderPattern):针对对象的创建过程比较复杂 类似建房子需要很多组件
who:创建对象时需要用到比较多的组件,比如需要用到其他类/方法
why:隐藏建造过程
how:new StringBulider("x"){super(16),append(x)}
write:
where:StringBulider(建造时需要创建arr/append)
3.4.原型模式(PrototypePattern):浅拷贝/深拷贝
who:即以旧对象为原型创造新的对象
why:如果一个类对象间的属性多而差异小,则可以用原型对象省去赋值的过程
how:object的clone方法即浅拷贝,需要重新clone方法才能实现深拷贝
write:
where:
ps:感觉使用范围好小,属性多的对象copy的时候可能相同 但后期维护又觉得可能需要改 并且可能clone这个对象时其值在多线程情况下被不可知的变更了
4.结构型模式–对象或类直接的关系 ABCDFFP
4.1.适配器(AdapterPattern):一个接口变成另外一个接口
who:通俗的讲就是讲一个接口变成另外一个接口
why:前期设计时没考虑到的,后期拓展时可以通过适配器去拓展原有的接口功能
how:适配器和目标类都实现同一接口,然后适配器重写这个接口,就可以搞定了哈
write:
where:RunnableAdapter/FutureAdapter
question:代码上看和装饰者以及代理都有点类似呀 –>都拓展原接口的方法 但核心区别在于适配器是为了将一个接口变成另外一个接口,装饰者是为了某个接口提供特定的功能拓展,代理是提供通用的功能拓展
class RunnableAdapter implements Callable<T>{
//两个属性
public RunnableAdapter(Runnable runnable,T result){
//构造方法赋值 this...=..
}
public T call(){
runnable.run();
return result;
}
}
4.2 桥接模式(BridgePattern)
who:两个继承体系间用用高级别的连接起来
why:聚合/组合原则;开闭原则
how:abstract Myclass{private IMyClass1 myclass1; private IMyClass myclass2}
Myclass又有自己的子类 myclass各有自己的体系 但和ImyClass1之间是松耦合的
write:
where:这个模式感觉日常经常使用
4.3 组合模式(ComponentPattern):树形结构专用
who:针对类的树形结构,而设计的解决方案,设计一个容器类,可以自动处理容器和叶子,而不用用户去区分处理
why:
how:
write:
where:树形结构的,如文件目录,SAX解析XML
4.4 装饰器模式(DecoratorPattern):拓展中 继承的另外一种形式
who:继承原接口并持有原接口的引用 并对其拓展
why:聚合/组合原则
how:
write:
where:IO中的BufferedRead/BufferedWriter是比较典型的
public class BufferedWriter implements Writer{
private Writer out;
public void flush() throws IOException{
synchronized (lock) {
flushBuffer();
out.flush();
}
}
}
4.5 享元模式:不常用
4.6 外观模式:不常用
4.7 代理模式(ProxyPattern)
who:对通用功能进行拓展
why:开闭原则
how:jdk InvocationHandle接口,动态的生成实现了目标的接口的类的class; cglib则是动态的继承并生成含有代理代码的字节码
write:
where:SpringAOP典型应用
ps:静态代理拓展性太差,实用性不强,研究价值不大
question:装饰者和动态代理都是拓展,区别在于装饰者是指定接口,定制版本,拓展定制功能,而动态代理不需要指定接口 是大众版本,对拓展出通用型的功能
5.行为型模式–职责区分/交互 模式较多 不常用的不研究了
5.1 策略模式(StrategyPattern):同一职责下有多种实现方法,策略模式就是解决算法的可替换
who:定义一系列算法,把它们一个个封装起来,并且使它们可互相替换
why:算法和客户 解耦
how:参考桥接模式,但并不关心算法的调用方是否会有子类实现
write:
where:这就有很多了呀 比如我们常写代码时有时也是用Object object或者以接口作为属性
question:和桥接模式有点类似,同样是持有接口而不是具体实现类的引用,便于替换,两者的差别主要在于桥接模式的核心思想是两个体系之间的松耦合,而策略模式的重点只停留在自己体系间的解耦
5.2 观察者模式(ObserverPattern):重点为交互,通知其他职责开始工作
who:
why:
how:class MyEvent{
open(){
//循环通知所有监听者
observer.update()
}
}
write:
where:各种事件监听就用到了观察者
5.3 模板方法模式(Template Method Pattern):抽象类定义一个模板,子类对其中某些方法进行实现
who:
why:代码复用,减少重复代码
how:子类需要实现的方法分为抽象方法 钩子方法 钩子方法实际上父类已经实现了 子类重写可以控制父类的行为
write:
where:spring中很多应用 如jdbcTemplate
5.4 迭代器模式(IteratiorPattern):不暴露内部表示的情况下 遍历集合
who:
why:将遍历的功能单独提取至迭代器接口,符合单一职责
how:
write:
where:毫无疑问的会想到java.util.Iteratior接口 ArrayList有专门的ArrayListIteratior;组合的对象集合
5.5 命令模式(CommandPattern):多个操作整合成一个命令 隐藏命令的内部细节 可回滚