策略模式
策略模式就是要应对规则变化和新规则加入对程序带来的影响。
比如实现一个fly方法有很多种方式,可以做火箭飞、可以带翅膀飞等,那么当添加新的方式的时候可有选择以下方案:
1、继承:
即将设计一个抽象类,里面有这个fly的抽象方法
- 父类提供该实现方法,简单易用,不具有灵活性,支持性差,因为子类需要重写该父类方法,有可能忘记重写
- 父类中实现一个抽象方法,每个类都要实现,不能复用代码
2、组合:
将fly设计成为接口,使得父类持有该接口, 并由接口代理飞行
- 多用组合少用继承
- has-a的概念
- 足够灵活,复用代码
可以得到结论:优先使用组合方式,将不变部分抽象为接口,面向接口而不是面向继承,从而达到多用组合少用继承的目的
实现
1、分离变化得到接口
2、策略的实现类:实现一些不同的策略
3、客户端持有该策略的对象
4、在客户端正确的组合和这些策略
点评
优点:
- 使用组合,架构灵活
- 富有弹性,较好的应对变化
- 代码复用性好(相对继承)
- 消除大量的条件语句
缺点:
- 客户端需要了解每个策略细节,因为每个客户端要选择自己适合的策略
- 增加策略就要增加对象,这样就增加了对象的数目
应用场景
什么情况适合策略模式:
- 许多相关的类仅仅是行为差异
- 运行时选取不同的算法变体
- 通过条件语句在多个分支中选取一个
在java中以下方法使用了策略模式:
sort方法
- Java.util.Collections#sort(List list, Comparator < ? super T > c)
- java.util.Arrays#sort(T[], Comparator < ? super T > c)
Context:是实际调用排序的代码,即Collections的类。可以看到,默认使用了TimSort进行排序,排序的算法与对象的compare具体实现无关。
Strategy:即具体的对象比较接口,Comparator。
ConcreteStrategy:具体的比较算法,通过Comparator实现。例如实现大小写敏感、大小写不敏感或任意规则的比对。
线程池的排队和拒绝策略
- ThreadPoolExecutor中的ThreadFactory和RejectedExecutionHandler
Context:ThreadPoolExecutor实际执行的方法execute()。按照用户设定的排队策略和拒绝任务的处理策略执行。
Strategy:这里排队策略和拒绝任务的处理策略提供了各自的接口,分别是BlockingQueue
ConcreteStrategy:具体的排队策略和拒绝任务的处理策略,JDK中都提供了默认的实现方法。可以实现接口自定义策略进行扩展。
http://www.importnew.com/12690.html
http://www.importnew.com/12853.html
http://www.cnblogs.com/zuoxiaolong/p/pattern8.html
模板方法
所谓模板方法模式就是在一个方法中定义一个算法的骨架,而将一些步骤延迟到子类中。模板方法使得子类可以在不改变算法结构的情况下,重新定义算法中的某些步骤。
模板方法模式就是基于继承的代码复用技术的。在模板方法模式中,我们可以将相同部分的代码放在父类中,而将不同的代码放入不同的子类中。
实现
抽象基类:定义了一个算法的步骤,这个方法一定是final的,因为所有的子类都是这么实现的,不允许子类改变,还有:定义了基本方法(每个子类都是这么实现的)和抽象方法(每个子类实现方式不同,abstract修饰无方法体)以及钩子函数(这个方法有个默认实现,同时也可以由子类实现,用于判断是否执行某些方法,protect修饰有方法体)
实现子类:重写抽象基类的protect方法,即抽象方法和钩子函数
http://www.importnew.com/23467.html
点评
缺点:继承单继承
应用场景
类加载器classloader
在ClassLoader中定义的算法顺序是:
1,首先看是否有已经加载好的类。
2,如果父类加载器不为空,则首先从父类类加载器加载。
3,如果父类加载器为空,则尝试从启动加载器加载。
4,如果两者都失败,才尝试从findClass方法加载。
findClass这个方法,并不是必须实现的,所以JDK选择留给程序员们自己选择是否要覆盖