一 工厂模式
工厂方法模式是创建型的设计模式之一,Android中的Activity里的各个生命周期方法都有使用到工厂方法
工厂方法的定义及使用场景
在任何需要生成复杂对象的地方,都可以使用工厂方法模式,定义一个用于创建类的接口,让子类决定实例化哪个类,
工厂模式的通用模式代码
工厂模式分为标准工厂模式,及其变种工厂模式,
一般来说标准的工厂方法模式需要一个工厂只生产一种产品,那么当产品种类特别多的时候工厂的数量就特别多,所以通常会使用一些工厂方法模式的变种
//抽象产品类
public abstract class Product {
//产品类的抽象方法
public abstract void method();
}
public class ConcreteProductA extends Product{
@Override
public void method() {
System.out.println("具体的产品A");
}
}
public class ConcreteProductB extends Product{
@Override
public void method() {
System.out.println("具体的产品B");
}
}
//抽象工厂类
public abstract class Factroy{
//抽象工厂方法
public abstract Product createProduct();
}
//具体工厂类
public class ConcreteFactory extends Factroy{
@Override
public Product createProduct() {
return new ConcreteProductA();
}
}
//客户端类
public class Client{
public static void main (String[] args){
Factroy factroy = new ConcreteFactory();
Product p = factroy.createProduct();
p.method();
}
}
上面主要分为四大模块,一是抽象工厂,其为工厂方法模式的核心;二是具体工厂,其实现了具体的业务逻辑;三是抽象产品,是工厂方法模式所创建的产品的父类;四是具体产品,为实现抽象产品的某个具体产品的对象。
为了更加方便的生产我们所需要的产品,我们可以利用反射的方式来实现:
//抽象工厂类
public abstract class Factroy{
//抽象工厂方法
public abstract<T extends Product> T createProduct(Class<T> product_cls);
}
//具体工厂类
public class ConcreteFactory extends Factroy{
@Override
public <T extends Product> T createProduct(Class<T> product_cls) {
Product p = null;
try {
p = (Product) Class.forName(product_cls.getName()).newInstance();
}catch (Exception e){
e.printStackTrace();
}
return (T) p;
}
}
//客户端类
public class Client{
public static void main (String[] args){
Factroy factroy = new ConcreteFactory();
Product p = factroy.createProduct(ConcreteProductA.class);
p.method();
}
}
通过放射,我们在生产所需要的产品时,只需将该产品的class传入factory的生产函数即可。
二、 抽象工厂模式
抽象工厂模式也是创建型设计模式之一,它跟工厂模式的区别是生产出来的产品是不确定的,它只是为创建一组相关或者相互依赖的对象提供一个接口,而不需要指定它们的具体类。
抽象工厂模式包含四部分:
抽象工厂类:声明一组用于创建一种产品的方法,每个方法对应一种产品
具体工厂子类:继承自抽象工厂类,根据当前抽象子类对应的系列,重写父类定义的对应行为。对应的具体产品不同,行为的实现方式也不同。
抽象产品类:定义当前类型抽象产品的操作,子类继承父类完成具体的操作。在抽象工厂模式中,可能会有多种抽象类的定义。
具体产品子类:根据当前类型继承自对应的抽象类,并根据系列的不同重写抽象类定义的实现。
抽象工厂模式 通用模式//抽象产品类A
public abstract class AbstractProductA {
//每个具体的产品子类需要实现的方法
public abstract void methodA();
}
//抽象产品类
public abstract class AbstractProductB {
//每个具体的产品子类需要实现的方法
public abstract void methodB();
}
//具体产品类A1
public class ConcreteProductA1 extends AbstractProductA{
@Override
public void methodA() {
System.out.println("具体产品A1的方法");
}
}
//具体产品类A2
public class ConcreteProductA2 extends AbstractProductA{
@Override
public void methodA() {
System.out.println("具体产品A2的方法");
}
}
//具体产品类B1
public class ConcreteProductB1 extends AbstractProductB{
@Override
public void methodB() {
System.out.println("具体产品B1的方法");
}
}
//具体产品类B2
public class ConcreteProductB2 extends AbstractProductB{
@Override
public void methodB() {
System.out.println("具体产品B2的方法");
}
}
//抽象工厂类
public abstract class AbstractFactroy{
//创建产品A的方法
public abstract AbstractProductA createProductA();
//创建产品B的方法
public abstract AbstractProductB createProductB();
}
//具体工厂类1
public class ConcreteFactory1 extends AbstractFactroy{
@Override
public AbstractProductA createProductA() {
return new ConcreteProductA1();
}
@Override
public AbstractProductB createProductB() {
return new ConcreteProductB1();
}
}
//具体工厂类2
public class ConcreteFactory2 extends AbstractFactroy{
@Override
public AbstractProductA createProductA() {
return new ConcreteProductA2();
}
@Override
public AbstractProductB createProductB() {
return new ConcreteProductB2();
}
抽象工厂模式显着的优点就是分离接口与实现,客户端使用抽象的工厂来创建需要的对象而客户端根本不知道具体的实现是谁,客户端只是面向产品的接口编程,使其从具体的产品实现中解耦,同时基于接口和实现的分离,使抽象工厂方法模式在切换产品类时更加灵活、容易,
它的缺点也很明显,一是对类文件的爆炸性增加,二是不太容易扩展新的产品类,因为每当我们增加一个产品类,就需要修改抽象工厂,那么所有的具体工厂类都需要修改。
三、 单例模式
单例模式是应用最广的模式之一,许多时候系统只需要一个全局对象,这样有利于我们协调系统整体的行为,单例模式确保某一个类只有一个实例,而且自行实例化并向整个系统提高这个实例。
单例模式有以下特点
* 单例类只能有一个实例
* 单例类必须自己创建自己的唯一实例
* 单例类必须给所有其他对象提供这一实例
**
单例模式的关键点:**
1.构造函数不对外开放,一般为Private
2.通过一个静态方法或枚举返回单例类对象
3.确保单例类的对象有且只有一个,尤其是在多线程的环境下
4.确保单例类对象在反序列化时不会重新构建对象
下面是单例模式的几种实现方式:
1.双重检查锁定DCL:
- 优点:资源利用率高,第一次执行getInstance才会实例化对象,效率高
- 缺点:第一次加载反应慢,也由于Java内存模型的原因偶尔会失败(由于Java编译器允许处理器乱序执行,以及JMM中cache、寄存器、到主内存回写的规定,singleton=new Singleton(); 这句正常的执行顺序:
1.改Singleton分配内存
2.调用Singleton()构造函数
3.将singleton对象指定分配的内存空间
可能无法按需要的顺序执行,变成 1 - 3 - 2,而导致执行3而未执行2之前被切换到另外一个线程,导致singleton不为空,但是又没有初始化Singleton,导致DCL失效
public class Singleton{
private Singleton(){}
private static volatile Singleton slinleton=null;
public static Singleton getInstance()
{
if(singleton==null)
{
synchronized(Singleton.class)
{
if(singleton==null)
{
singleton=new Singleton();
}
}
}
return singleton;
}
}
2.静态内部类 :推荐使用 ,线程安全
public class Singleton{
private Singleton(){}
private static class LazyHolder{
private static final Singleton INSTANCE=new Singleton();
}
public static Singleton getInstance()
{
return LazyHolder.INSTANCE;
}
}
在Android系统中,如WidowsManagerService,ActivityManagerService,LayouInflater等类,都是在合适的时候以单例形式注册在系统中的。
四、 Builder建造者模式
Builder模式是一步一步创建一个复杂对象的创建型模式,将一个复杂对象的构建和它的表示分离,使得同样的构建过程可以创建不同的表示。
使用场景:
1.相同的方法,不同的执行顺序,昌盛不同的事件结果时。
2.多个部件或零件,都可以装配到一个对象中,但是产生的运行结果又不相同时。
3.产品类非常复杂,或者产品类的调用顺序不同产生了不同的作用,这个时候使用建造者非常合适。
4.当初始化一个对象特别复杂,如参数多,且很多参数都具有默认值时。
Builder模式的主要角色:
- Product产品类——产品的抽象类
- Builder ——抽象Builder类,规范产品的组建,一般由子类实现具体的组件过程;
- ConcreteBuilder ——具体的Builder类
- Director ——统一组装过程。
Builder模式的简单实现
package com.example.zjz.utils;
import android.content.SyncStatusObserver;
import android.nfc.tech.MifareUltralight;
import android.os.Bundle;
import android.support.annotation.VisibleForTesting;
/**
* Created by 5555 on 2017/1/7 0007.
*/
/计算机抽象类
abstract class Computer {
protected String mBoard;
protected String mDisplay;
protected String mOS;
protected Computer() {
}
//设置CPU核心数
public void setBoard(String board) {
mBoard = board;
}
//设置内存
public void setDisplay(String display) {
mDisplay = display;
}
//设置操作系统
public abstract void setmOS();
@Override
public String toString() {
return "Computer [mVoard=" + mBoard + ",mDisplay=" + mDisplay + ",mOS=" + mOS + "]";
}
}
//具体的Computer类,MacBook
class MacBook extends Computer {
@Override
public void setmOS() {
mOS = "Mac OS X 10.10";
}
}
//抽象Builder类
abstract class Builder{
//设置主机
public abstract void buildBoard(String board);
//设置显示器
public abstract void buildDisplay(String display);
//设置操作系统
public abstract void buildOS();
//创建Computer
public abstract Computer create();
}
//具体的Builder类,
class MacBookBuilder extends Builder{
private Computer mComputer = new MacBook();
@Override
public void buildBoard(String board) {
mComputer.setBoard(board);
}
@Override
public void buildDisplay(String display) {
mComputer.setDisplay(display);
}
@Override
public void buildOS() {
mComputer.setmOS();
}
@Override
public Computer create() {
return mComputer;
}
}
//负责构造Builder类
class Director{
Builder mBuilder =null;
public Director(Builder builder){
mBuilder = builder;
}
public void construct(String board, String display){
mBuilder.buildBoard(board);
mBuilder.buildDisplay(display);
mBuilder.buildOS();
}
}
public class TestBuilder{
public static void main(String[] args){
Builder builder = new MacBookBuilder();
Director pcDirector = new Director(builder);
pcDirector.construct("intelBoard","Retina显示器");
System.out.println("Computerr Info: "+builder.create().toString());
}
}
通过上述代码,我们可以清晰的看到,通过使用Builder模式,用户在生成所需类的时候,只需将需要的参数传入,而不需要知道产品内部的组成细节,具有良好的封装性,这也体现了建造者模式独立,且容易扩展的特点。
Builder模式在Android开发中也较为常用,通常作为配置类的构建器将配置的构建和表示分离开来,同时也是将配置从目标类中隔离出来,避免过多的setter方法,Builder常见的实现形式是通过调用链实现的使代码更加的简洁易懂。
五、 适配器模式
适配器模式在Android中应用十分广泛,我们常见的ListView、RecyclerView等都需要使用Adapter。
适配器的定义是把一个类的接口变换成客户端所期待的另一种接口,从而使原本因接口不匹配而无法在一起工作的两个类能够在一起工作。
使用场景:
1.系统需要使用现有的类,而此类的接口不符合系统的需求,即接口不兼容
2.想要建立一个可以重复使用的类,用于与一些之间没有太大关联的一些类,包括一些可能在将来引进的类一起工作。
3.需要一个统一的输出接口,而输入端的类型不可预知。
适配器模式有三个角色:
- Target :目标角色,就是所期待得到的接口,
- Adaptee:现在需要适配的接口
- Adapter:适配器角色,也是本模式的核心,适配器把原接口装换成目标接口。显然,这一角色不可以是接口,而必须是类。
适配器模式分为类适配器模式和对象适配器模式。类适配器模式是用Adapter继承Adaptee来实现关联,
而对象适配器是通过Adapter聚合Adaptee的方式实现关联。
简单示例
本例是电压装换示例,电器工作电压是5V,而现有电压是220v,则5V电压就是Target接口,220V电压就是Adaptee类,将电压从220V转到5V就是Adapter。
- 类适配器模式:
//Target角色
public interface FiveVolt{
public int getVolt5();
}
//Adaptee角色,需要被转换的对象
public class Volt220{
public int getVolt220(){
return 220;
}
}
//Adapter角色,将220V的电压装换成5V的电压
public class VoltAdapter extends Volt220 implements FiveVolt{
@Override
public int getVolt5() {
return 5;
}
}
//测试
public class Test{
public static void main(String [] args){
VoltAdapter adapter = new VoltAdapter();
System.out.println("输出电压"+adapter.getVolt5());
}
}
- 对象适配器模式:
//Target角色
public interface FiveVolt{
public int getVolt5();
}
//Adaptee角色,需要被转换的对象
public class Volt220{
public int getVolt220(){
return 220;
}
}
//Adapter角色,将220V的电压装换成5V的电压
public class VoltAdapter implements FiveVolt{
Volt200 mVolt220;
pbulic VoltAdapter(Volt220 adaptee){
mVolt220 = adaptee;
}
public int getVolt220(){
return mVolt220.getVolt220();
}
@Override
public int getVolt5() {
return 5;
}
}
//测试
public class Test{
public static void main(String [] args){
VoltAdapter adapter = new VoltAdapter();
System.out.println("输出电压"+adapter.getVolt5());
}
}
这种实现方式是将Adaptee传递到Adapter中,使用组合的方式实现接口兼容的效果,这比类适配器方式更加灵活,另一个好处就是被适配对象中的方法不会暴露出来。
适配器模式的优缺点
优点:
- 更好的复用性,系统需要使用现有的类,而此类不符合系统的需要,通过适配器模式可以让这些功能更好的复用
- 更好的扩展性,在实现适配器功能的时候,可以调用自己开发的功能,从而自然地扩展系统的功能。
缺点:
- 过多的使用适配器,会让系统非常零乱,不易整体把握,如果不是很有必要,可以不适用适配器,二是直接对系统进行重构。
六 代理模式
代理模式是结构性设计模式,定义是为其他的对象提供一种代理已控制对这个对象的访问。
使用场景
当无法或不想直接访问某个对象或访问某个对象存在困难时,可以通过一个代理对象来间接访问,为了保证客户端的使用的透明性,委托对象与代理对象需要实现相同的接口。
通用模式代码
//抽象主题类
public abstract class Subject{
//普通的业务方法
public abstract void visit();
}
public class RealSubject extends Subject{
@Override
public void visit() {
System.out.println("Real subject");
}
}
//代理类
public class ProxySubject extends Subject{
private RealSubject mSubject; //持有真实主题的引用
public ProxySubject(RealSubject subject){
this.mSubject = subject;
}
@Override
public void visit() {
mSubject.visit();
}
}
//客户端类
public class Client{
public static void main (String[] args){
//构建一个真实主题对象
RealSubject realSubject = new RealSubject();
//通过真实主题引用的对象构造一个代理对象
ProxySubject proxySubject = new ProxySubject(realSubject);
//调用代理的相关方法
proxySubject.visit();
}
}
- Subject:抽象主题类,该类的主要职责是声明真实主题与代理的共同接口方法,该类既可以是一个抽象类也可以是一个接口。
- RealSubject:真实主题类,该类也称为主题类或被代理类,定义了代理所表示的真实对象,由其执行具体的业务逻辑方法,而客户类则通过代理类间接地调用真实主题类中定义的方法。
- ProxySubject:代理类,该类持有一个对真实主题类的引用,在其所实现的接口方法中调用真实主题类中相应的接口方法执行,以此实现代理的作用。
- Client:客户类,即使用代理类的类型。
上面例子所列出的是静态代理模式,代理模式还有另外一种,就是动态代理模式,
java动态代理创建对象的过程为如下步骤:
1,通过实现 InvocationHandler 接口创建自己的调用处理器;
// InvocationHandlerImpl 实现了 InvocationHandler 接口,并
能实现方法调用从代理类到委托类的分派转发
// 其内部通常包含指向委托类实例的引用,用于真正执行分派转发过来的方法调用
InvocationHandler handler = new InvocationHandlerImpl(..);
2,通过为 Proxy 类指定 ClassLoader 对象和一组 interface 来创建动态代理类;
// 通过 Proxy 为包括 Interface 接口在内的一组接口动态创建代理类的类对象
Class clazz = Proxy.getProxyClass(classLoader, new Class[] { Interface.class, ... });
3,通过反射机制获得动态代理类的构造函数,其唯一参数类型是调用处理器接口类型;
// 通过反射从生成的类对象获得构造函数对象
Constructor constructor = clazz.getConstructor(new Class[]
{ InvocationHandler.class });
4,通过构造函数创建动态代理类实例,构造时调用处理器对象作为参数被传入。
// 通过构造函数对象创建动态代理类实例
Interface Proxy = (Interface)constructor.newInstance(new Object[] { handler });
为了简化对象创建过程,Proxy类中的newProxyInstance方法封装了2~4,只需两步即可完成代理对象的创建。
// InvocationHandlerImpl 实现了 InvocationHandler 接口
,并能实现方法调用从代理类到委托类的分派转发
InvocationHandler handler = new InvocationHandlerImpl(..);
// 通过 Proxy 直接创建动态代理类实例
Interface proxy = (Interface)Proxy.newProxyInstance( classLoader,
new Class[] { Interface.class },
handler );
代理模式的优缺点:
- 优点:
1.代理作为调用着和真实对象的中间层,降低了模块间和系统的耦合性
2.可以以一个小对象代理一个大对象,达到优化系统提高运行速度的目的
3.提供RealSubject的权限管理
4.容易扩展,RealSubject和ProxySubject都接口化了,RealSubject更改业务后只要接口不变,ProxySubject可以不做任何修改.
- 缺点:
1.因为调用者和真实对象多了一个中间层,所以会增加调用响应的时间
七 观察者模式
观察者模式常用于 GUI系统,订阅——发布系统,因为这个模式一个重要作用就是解耦,他的定义是定义对象间的一种一对多的依赖关系,当一个对象的状态发送改变时,所有依赖于它的对象都能得到通知并被自动更新
使用场景
- 关联行为场景,需要注意的是,关联行为是可拆分的,而不是“组合”关系;
- 事件多级触发场景
- 跨系统的消息交换场景,如消息队列、事件总线的处理机制
观察者模式的几个重要组成。
- 观察者,我们称它为Observer,有时候我们也称它为订阅者,即Subscriber
- 被观察者,我们称它为Observable,即可以被观察的东西,有时候还会称之为主题,即Subject
至于观察者模式的具体实现,这里带带大家实现一下场景一,其实Java中提供了Observable类和Observer接口供我们快速的实现该模式,但是为了加深印象,我们不使用这两个类。
场景1中我们感兴趣的事情是天气预报,于是,我们应该定义一个Weather实体类。
public class Weather {
private String description;
public Weather(String description) {
this.description = description;
}
、、获取天气情况
public String getDescription() {
return description;
}
//设置天气情况
public void setDescription(String description) {
this.description = description;
}
@Override
public String toString() {
return "Weather{" +
"description='" + description + '\'' +
'}';
}
}
然后定义我们的被观察者,我们想要这个被观察者能够通用,将其定义成泛型。内部应该暴露register和unregister方法供观察者订阅和取消订阅,至于观察者的保存,直接用ArrayList即可,此外,当有主题内容发送改变时,会即时通知观察者做出反应,因此应该暴露一个notifyObservers方法,以上方法的具体实现见如下代码。
public class Observable<T> {
List<Observer<T>> mObservers = new ArrayList<Observer<T>>();
public void register(Observer<T> observer) {
if (observer == null) {
throw new NullPointerException("observer == null");
}
synchronized (this) {
if (!mObservers.contains(observer))
mObservers.add(observer);
}
}
public synchronized void unregister(Observer<T> observer) {
mObservers.remove(observer);
}
public void notifyObservers(T data) {
for (Observer<T> observer : mObservers) {
observer.onUpdate(this, data);
}
}
}
而我们的观察者,只需要实现一个观察者的接口Observer,该接口也是泛型的。其定义如下。
public interface Observer<T> {
void onUpdate(Observable<T> observable,T data);
}
一旦订阅的主题发送变换就会回调该接口。
我们来使用一下,我们定义了一个天气变换的主题,也就是被观察者,还有两个观察者观察天气变换,一旦变换了,就打印出天气信息,注意一定要调用被观察者的register进行注册,否则会收不到变换信息。而一旦不敢兴趣了,直接调用unregister方法进行取消注册即可
public class Main {
public static void main(String [] args){
Observable<Weather> observable=new Observable<Weather>();
Observer<Weather> observer1=new Observer<Weather>() {
@Override
public void onUpdate(Observable<Weather> observable, Weather data) {
System.out.println("观察者1:"+data.toString());
}
};
Observer<Weather> observer2=new Observer<Weather>() {
@Override
public void onUpdate(Observable<Weather> observable, Weather data) {
System.out.println("观察者2:"+data.toString());
}
};
observable.register(observer1);
observable.register(observer2);
Weather weather=new Weather("晴转多云");
observable.notifyObservers(weather);
Weather weather1=new Weather("多云转阴");
observable.notifyObservers(weather1);
observable.unregister(observer1);
Weather weather2=new Weather("台风");
observable.notifyObservers(weather2);
}
}
输出:
观察者1:Weather{description=’晴转多云’}
观察者2:Weather{description=’晴转多云’}
观察者1:Weather{description=’多云转阴’}
观察者2:Weather{description=’多云转阴’}
观察者2:Weather{description=’台风’}
观察者模式主要的作用就是对象解耦,将观察者和被观察者完全隔离,只依赖于Observer和Observable抽象
- 优点:1
1.观察者和被观察者之间是抽象耦合,应对业务变化
2.增强系统的灵活性,可扩展性
- 缺点在应用观察者模式时应该考虑一下开发效率和运行效率问题,程序中包括一个被观察者、多个观察者、开发和调试等内容会比较复杂,
八 策略模式
使用场景
- 针对同一类型问题的多种处理方式,仅仅是具体行为有差别时
- 需要安全地封装多种同一类型的操作时
- 出现同一抽象类有多个子类,而又需要使用if-else或者switch-case来选择具体子类时
这个模式涉及到三个角色:
环境(Context)角色:持有一个Strategy的引用。
抽象策略(Strategy)角色:这是一个抽象角色,通常由一个接口或抽象类实现。此角色给出所有的具体策略类所需的接口。
具体策略(ConcreteStrategy)角色:包装了相关的算法或行为。
代码例子
1.角色环境类
public class Context {
//持有一个具体策略的对象
private Strategy strategy;
/**
* 构造函数,传入一个具体策略对象
* @param strategy 具体策略对象
*/
public Context(Strategy strategy){
this.strategy = strategy;
}
/**
* 策略方法
*/
public void contextInterface(){
strategy.strategyInterface();
}
}
2.抽象策略类
public interface MemberStrategy {
/**
* 计算图书的价格
* @param booksPrice 图书的原价
* @return 计算出打折后的价格
*/
public double calcPrice(double booksPrice);
}
3.具体策略类(初级会员折扣)
p
ublic class PrimaryMemberStrategy implements MemberStrategy {
@Override
public double calcPrice(double booksPrice) {
System.out.println("对于初级会员的没有折扣");
return booksPrice;
}
}
4.具体策略类(中级会员折扣)、
public class IntermediateMemberStrategy implements MemberStrategy {
@Override
public double calcPrice(double booksPrice) {
System.out.println("对于中级会员的折扣为10%");
return booksPrice * 0.9;
}
}
5.具体策略类(高级会员折扣)、
public class AdvancedMemberStrategy implements MemberStrategy {
@Override
public double calcPrice(double booksPrice) {
System.out.println("对于高级会员的折扣为20%");
return booksPrice * 0.8;
}
}
6.价格类
public class Price {
//持有一个具体的策略对象
private MemberStrategy strategy;
/**
* 构造函数,传入一个具体的策略对象
* @param strategy 具体的策略对象
*/
public Price(MemberStrategy strategy){
this.strategy = strategy;
}
/**
* 计算图书的价格
* @param booksPrice 图书的原价
* @return 计算出打折后的价格
*/
public double quote(double booksPrice){
return this.strategy.calcPrice(booksPrice);
}
}
客户端
public class Client {
public static void main(String[] args) {
//选择并创建需要使用的策略对象
MemberStrategy strategy = new AdvancedMemberStrategy();
//创建环境
Price price = new Price(strategy);
//计算价格
double quote = price.quote(300);
System.out.println("图书的最终价格为:" + quote);
}
}
从上面的示例可以看出,策略模式仅仅封装算法,提供新的算法插入到已有系统中,以及老算法从系统中“退休”的方法,策略模式并不决定在何时使用何种算法。在什么情况下使用什么算法是由客户端决定的。
策略模式的重心
策略模式的重心不是如何实现算法,而是如何组织、调用这些算法,从而让程序结构更灵活,具有更好的维护性和扩展性。
算法的平等性
策略模式一个很大的特点就是各个策略算法的平等性。对于一系列具体的策略算法,大家的地位是完全一样的,正因为这个平等性,才能实现算法之间可以相互替换。所有的策略算法在实现上也是相互独立的,相互之间是没有依赖的。
所以可以这样描述这一系列策略算法:策略算法是相同行为的不同实现。
运行时策略的唯一性
运行期间,策略模式在每一个时刻只能使用一个具体的策略实现对象,虽然可以动态地在不同的策略实现中切换,但是同时只能使用一个。
公有的行为
经常见到的是,所有的具体策略类都有一些公有的行为。这时候,就应当把这些公有的行为放到共同的抽象策略角色Strategy类里面。当然这时候抽象策略角色必须要用Java抽象类实现,而不能使用接口。
- 优点
每个算法都独立于其他,方便单元测试
结构更加清晰,不会像一堆条件语句让你看着头晕
客户端引用的是接口,耦合度更低,扩展性更强
- 缺点
随着策略增加,子类会增加