策略模式
定义:
策略模式定义了一系列的算法,并将每一个算法封装起来,而且使他们可以相互替换,让算法独立于使用它的客户而独立变化。(多态)
类图:
说明:
环境(Context)角色:持有一个Strategy的引用。屏蔽外界对于策略算法的直接访问。
抽象策略(Strategy)角色:这是一个抽象角色,通常由一个接口或抽象类实现。此角色给出所有的具体策略类所需的接口。
具体策略(ConcreteStrategy)角色:包装了相关的算法或行为。
代码举例:
//抽象策略类
public interface Strategy {
/**
* 策略方法
*/
public void strategyInterface();
}
//具体策略类
public class ConcreteStrategyA implements Strategy {
@Override
public void strategyInterface() {
//相关的业务
}
}
public class ConcreteStrategyB implements Strategy {
@Override
public void strategyInterface() {
//相关的业务
}
}
//环境角色类
public class Context {
//持有一个具体策略的对象
private Strategy strategy;
/**
* 构造函数,传入一个具体策略对象
* @param strategy 具体策略对象
/
public Context(Strategy strategy){
this.strategy = strategy;
}
/*
* 策略方法
*/
public void contextInterface(){
strategy.strategyInterface();
}
}
使用场景:
1.针对同一类型问题的多种处理方式,仅仅是具体行为有差别时; 2.需要安全地封装多种同一类型的操作时; 3.出现同一抽象类有多个子类,而又需要使用 if-else 或者 switch-case 来选择具体子类时。
优缺点
优点:
1.策略模式提供了管理相关的算法族的办法。策略类的等级结构定义了一个算法或行为族。恰当使用继承可以把公共的代码转移到父类里面,从而避免重复的代码。
2.使用策略模式可以避免使用多重条件转移语句。多重转移语句不易维护,它把采取哪一种算法或采取哪一种行为的逻辑与算法或行为的逻辑混合在一起,统统列在一个多重转移语句里面,比使用继承的办法还要原始和落后。
缺点:
1.客户端必须知道所有的策略类,并自行决定使用哪一个策略类。这就意味着客户端必须理解这些算法的区别,以便适时选择恰当的算法类。换言之,策略模式只适用于客户端知道所有的算法或行为的情况。
2.策略模式造成很多的策略类,每个具体策略类都会产生一个新类。有时候可以通过把依赖于环境的状态保存到客户端里面,而将策略类设计成可共享的,这样策略类实例可以被不同客户端使用。换言之,可以使用享元模式来减少对象的数量。
与工厂模式区别与联系:
联系:
在模式结构上,两者很相似;
用if else 也能实现,用了设计模式之后让代码高级起来
区别:
用途: 工厂是创建型模式,它的作用就是创建对象; 策略是行为型模式,它的作用是让一个对象在许多行为中选择一种行为;
常用应用场景:
Android的源码中,策略模式最典型的就是属性动画中的应用
例子:
1.注解+工厂+策略模式实现四种玩家不同收费标准https://blog.csdn.net/u012124438/article/details/70039943/
2.策略模式和Spring注解的结合在项目中的应用 https://blog.csdn.net/zlts000/article/details/54754789
不变模式
定义:
一个对象的状态在对象被创建之后就不再发生变化
分为两类:一 弱不变模式 二,强不变模式.区分在于 有没有限制其子类是否可变!
弱不变模式的创建条件:
一,不存在可以修改这个类的方法
二,这个类的属性全部为私有属性,防止客户端修改这些属性
三,如果这类内部引用了外部的对象,那么尽可能防止客户端修改这个对象,可以直接在不变类的内部初始化这个对象,如果这个对象必须由客户端传入,那么不直接使用这个对象,而是使用这个对象的clone
强不变模式的创建条件:满足其中一个即可
一. 所有方法为final,防止子类可以修改不变父类
二,不变类直接是final类.这样就没有子类,也就不存在子类可以修改父类的隐患
代码举例
//弱不变
pubilc final class Product{
private final String no;
private final String name;
public Product (String no,String name){
super();
this.no=no;this.name=name;
}
public String getNo(){
return no;
}
public String getName(){
return name;
}
}
场景:
Java的String就是一个强不变类。String类实际上是一个封装类,因为它包装了一个char的数组。还有其他的:Integer、Double等。有了封装类,就可以把原始数据类型包装为对象处理。这些也都是强不变类。
优缺点:
优点
不修改一个不变对象,可以避免由此引起的不必要的程序错误,所以更加容易维护。
一个不可变对象是线程安全的,这样就可以省掉处理同步化的开销,可以自由的被共享。
缺点
一旦需要修改状态,就只能创建一个新的同类对象,在需要频繁修改不变对象的环境里,会有大量的对象作为中间结果创建,造成资源浪费。
模板方法
定义:
定义一个算法中的操作框架,而将一些步骤延迟到子类中。使得子类可以不改变算法的结构即可重定义该算法的某些特定步骤。(就是在抽象类中定义一些模板算法,子类直接继承)
类图:
(使用了java的继承)
说明:
AbstractClass叫做抽象模板,它的方法分为两类:
基本方法:是由子类实现的方法,并且在模板方法被调用。(抽象模板中的基本方法尽量设计为protected类型,符合迪米特法则,不需要暴露的属性或方法尽量不要设置为protected类型。实现类若非必要,尽量不要扩大父类中的访问权限)
模板方法:可以有一个或几个,一般是一个具体方法,也就是一个框架,实现对基本方法的调用,完成固定的逻辑。(一般都加上final关键字,防止被覆写)
代码实现;
public abstract class AbstractClass {
protected abstract void doAnything();
protected abstract void doSomething();
public final void templateMethod(){
/*
* 调用基本方法,完成相关的逻辑
*/
this.doAnything();
this.doSomething();
}
}
public class ConcreteClass1 extends AbstractClass {
@Override
protected void doAnything() {
// TODO Auto-generated method stub
//子类实现具体
}
@Override
protected void doSomething() {
// TODO Auto-generated method stub
}
}
public class ConcreteClass2 extends AbstractClass {
@Override
protected void doAnything() {
// TODO Auto-generated method stub
//子类实现具体
}
@Override
protected void doSomething() {
// TODO Auto-generated method stub
}
}
优缺点:
优点:
封装不变部分,扩展可变部分。把认为不变部分的算法封装到父类中实现,而可变部分的则可以通过继承来继续扩展。
提取公共部分代码,便于维护。
行为由父类控制,子类实现。
缺点:
按照设计习惯,抽象类负责声明最抽象、最一般的事物属性和方法,实现类负责完成具体的事务属性和方法,但是模板方式正好相反,子类执行的结果影响了父类的结果,会增加代码阅读的难度。
使用场景
多个子类有共有的方法,并且逻辑基本相同
重要、复杂的算法,可以把核心算法设计为模板方法,周边的相关细节功能则由各个子类实现
重构时,模板方法是一个经常使用的方法,把相同的代码抽取到父类中,然后通过构造函数约束其行为。
拓展:
子类控制父类模板方法的执行
若在ConcreteClass2中不想执行doSomething()方法,
public abstract class AbstractClass {
protected abstract void doAnything();
protected abstract void doSomething();
protected boolean isDoSomething(){ //父类方法返回真
return true;
}
public final void templateMethod(){
/*
* 调用基本方法,完成相关的逻辑
*/
this.doAnything();
if(this.isDoSomething())
this.doSomething();
}
}
public class ConcreteClass1 extends AbstractClass {
private boolean isDoSth;
@Override
protected void doAnything() {
// TODO Auto-generated method stub
//子类实现具体
}
@Override
protected void doSomething() {
// TODO Auto-generated method stub
}
protected void setDo(boolean isDo){
this.isDoSth = isDo;
}
protected boolean isDoSomething(){
return isDoSth;
}
}
最佳实践:
模板方法模式是通过父类建立框架,子类在重写了父类部分方法之后,在调用从父类继承的方法,产生不同的效果,通过修改子类,影响父类行为的结果,模板方法在一些开源框架中应用非常多,它提供了一个抽象类,然后开源框架写了一堆子类,如果需要扩展功能,可以继承此抽象类,然后覆写protected基本方法,然后在调用一个类似TemplateMethod()的模板方法,完成扩展开发。
与策略模式比较
模版方法:控制算法内部。 基于继承
策略模式:不同算法的管理。 基于多态
实例:
模板方法模式