Java设计模式之二——策略模式

又是一个阳光明媚的周末。岁月静好,浅笑安然!


一、前言

在讲策略模式之前,先来看一下JDK源码中java.util.Arrays类的一个对象排序的方法,如下截图:


主要看1544行,我们可以知道,这个mergeSort()排序方法的实现过程中,for循环中调用compare方法的对象c是我们自己外部传入的。我们自己定义的对象比较的类c实现了Comparator接口,并且实现了该接口中的compare(T, T)方法,然后进行具体的排序工作。所以,JDK提供的Arrays类的这个排序方法,实际上使用的排序算法是我们自己定义好的;这样的话,我们自己传入什么排序算法,就可以进行什么方式的排序,非常灵活。这就是策略模式思想。

二、什么是策略模式

1、策略模式的定义

策略模式它定义了一组算法,并且将每个算法都封装起来,各个算法可以灵活的相互切换。就像上面介绍的排序算法一样,我们自己定义的多个算法,然后根据应用程序的需要传入,就可以非常方便的按照我们自己的算法进行排序。


2、策略模式的有点

1)、策略模式很好的体现了拥抱变化,封装变化的概念。该模式在编程过程中使用接口,即面向接口编程。

2)、策略模式使得客户端在使用这些算法的时候,可以非常方便、灵活的互换且互相不影响。

3)、策略模式使得开发人员可以开发出各种可以互相替换的软件组件,并且各个组件之间是弱连接的关系。这就使

得软件具有更好更强的可扩展性和易维护性。更重要的是,它大大提高了软件的可重用性。


3、策略模式的各个组成角色

策略模式主要由以下3个角色组成:

1)、抽象策略角色:也就是策略类,它通常由一个接口或者抽象类来实现。

2)、具体策略角色:实现了抽象策略角色,包装了一组相关的算法和行为。

3)、环境角色:该角色持有一个策略类的引用,且该引用的类型是抽象策略类的类型。该角色最终给客户端调用。


4、策略模式的编写步骤

1)、对策略对象定义一个公共的接口,即定义抽象策略类。

2)、编写具体策略类,该策略类实现上面的抽象策略类。

3)、在使用策略对象的类(即环境角色)中持有一个对策略对象的引用。

4)、还要在环境角色中实现对策略对象的设值(set)和取值(get),或者使用构造方法完成对策略对象的赋值。

5、具体事例代码如下


1、抽象策略类:

package com.strategy.pattern.demo;

/**
 * 
 * @ClassName: CarProduceStrategy
 * @Description: 抽象策略角色,制造汽车
 * @author admin
 * @date 2016年12月3日 上午10:44:11
 * @version V1.0
 */
public interface CarProduceStrategy {

	public void produceCar();
}

2、下面是3个具体策略类,实现了抽象策略类,且实现了抽象策略类中的方法:

package com.strategy.pattern.demo;

/**
 * 
 * @ClassName: BMWProduce
 * @Description: 具体策略类,制造宝马品牌的汽车
 * @author admin
 * @date 2016年12月3日 上午10:46:20
 * @version V1.0
 */
public class BMWProduce implements CarProduceStrategy {

	@Override
	public void produceCar() {

		System.out.println("宝马汽车制造...");
	}
}


package com.strategy.pattern.demo;

/**
 * 
 * @ClassName: BENZProduce 
 * @Description: 具体策略类,制造奔驰品牌的汽车
 * @author admin
 * @date 2016年12月3日 上午10:46:20
 * @version V1.0
 */
public class BENZProduce implements CarProduceStrategy {

	@Override
	public void produceCar() {

		System.out.println("奔驰汽车制造...");
	}
}


package com.strategy.pattern.demo;

/**
 * 
 * @ClassName: AUDIProduce
 * @Description: 具体策略类,制造奥迪品牌的汽车
 * @author admin
 * @date 2016年12月3日 上午10:46:20
 * @version V1.0
 */
public class AUDIProduce implements CarProduceStrategy {

	@Override
	public void produceCar() {

		System.out.println("奥迪汽车制造...");
	}
}

3、环境角色:

package com.strategy.pattern.demo;

/**
 * 
 * @ClassName: Environment
 * @Description: 环境角色
 * @author admin
 * @date 2016年12月3日 上午10:51:30
 * @version V1.0
 */
public class Environment {

	private CarProduceStrategy produceStrategy;
	
	public Environment(CarProduceStrategy produceStrategy) {

		this.produceStrategy = produceStrategy;
	}

	public CarProduceStrategy getProduceStrategy() {
		return produceStrategy;
	}

	public void setProduceStrategy(CarProduceStrategy produceStrategy) {
		this.produceStrategy = produceStrategy;
	}
	
	/**
	 * 
	 * @Title: produceCar
	 * @Description: 调用具体的某个策略进行汽车制造
	 * @param 
	 * @return void 
	 * @throws
	 */
	public void produceCar(){
		
		produceStrategy.produceCar();
	}
}

4、客户端:

package com.strategy.pattern.demo;

/**
 * 
 * @ClassName: Client
 * @Description: 具体策略调用者,客户端
 * @author admin
 * @date 2016年12月3日 上午10:54:26
 * @version V1.0
 */
public class Client {

	public static void main(String[] args) {
		
		CarProduceStrategy produceStrategy = new BMWProduce();
		
		//宝马汽车制造策略
		Environment environment = new Environment(produceStrategy);
		environment.produceCar();
		
		//奔驰汽车制造策略
		produceStrategy = new BENZProduce();
		environment.setProduceStrategy(produceStrategy);
		environment.produceCar();
		
		//奥迪汽车制造策略
		produceStrategy = new AUDIProduce();
		environment.setProduceStrategy(produceStrategy);
		environment.produceCar();
	}
}

5、测试打印结果:



三、总结

从上面的例子可以看出,策略模式其实还是比较容易理解和实现的。但是,有没有发现什么问题呢?假如我们

还要实现一个制造大众品牌的汽车,我们会怎么写?毫无疑问,我们会在写一个策略类,去实现抽象策略类,并且实现里面的抽象方法来实现制造大众品牌的汽车的逻辑。这样在逻辑上是没任何问题,但是在上升到编程规范和艺术上来说,问题很明显:

1、会导致我们的系统拥有很多的策略类。

2、由于系统拥有大量策略类,这就要求客户端必须知道系统中所有的策略类,并自行决定使用哪一个策略类。


      四、解决办法:采用工厂方法。


未完待续。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值