Java设计模式之策略模式

Java设计模式之策略模式

 

        摘要:本篇笔记主要是对策略模式(StrategyPattern)学习过程、心得的记录。主要是通过模仿JDK中关于类的比较的方式来实现可以使用指定的方法、指定的策略来比较两个类的大小。

 

一:简介

 

        三十六计走为上策、这句话我们肯定不会陌生!策略、就是我们针对不同的时期、或者不同的情况、动态的选择合适的应对方式、这种应对方式可以称作是一种策略。

        Java的设计模式的原则中不会少得了flexible、extensible。下面通过模仿JDK的比较方式来展示策略模式的设计思想。当然一口吃不成胖子、还是老套路、围绕问题去一步一步深入探索。

 

二:问题的引出及解决

 

        1、给你一个int型数组、如何调用别的类对其进行排序?

 

                是不是觉得没什么难度?这里就暂时不要考虑JDK为我们提供的Arrays.sort(Object[] o)这种已经实现的工具类、假设没有、完全要我们自己去实现。你怎么实现?下面是一种实现:

                a)、 先写测试类、这样的一个好处就是你知道下一步要干嘛——Client代码:


package com.chy.dp.strategy;

public class Client {
	public static void main(String[] args) {
		int[] a = {3,4,2,5,1};
		DataSort.sort(a);
		DataSort.print(a);
	}
}

                b)、 实现测试类中DataSort代码:

       

package com.chy.dp.strategy;

public class DataSort {

	/**
	 * there many ways to sort an array, 
	 * but i just use the bubble sort to sort it.
	 * i'll use other ways to sort it if i has more time.
	 * @param a	the array will be sorted.
	 */
	public static void sort(int[] a) {
		for (int j = 0; j < a.length; j++) {
			for (int i = 0; i < a.length - j -1; i++) {
				if(a[i] > a[i + 1]){
					swap(a, i, i+1);
				}
			}
		}
	}

	/**
	 * change the two elements of an array.
	 * @param a an array.
	 * @param i	the first element index.
	 * @param j	the next element index.
	 */
	private static void swap(int[] a, int i, int j) {
		int temp = a[i];
		a[i] = a[j];
		a[j] = temp;
	}

	public static void print(int[] a) {
		for (int i = 0; i < a.length; i++) {
			System.out.print(a[i] + " ");
		}
	}
}


        2、给你一个猫的数组、如何调用别的类对其进行排序?


               两只猫怎么比较?给你一个标准、猫有一个身高、一个体重、根据身高来比较猫的大小、这样一来是不是也觉得没什么难度?

               a) 要比较猫、当然要有一个Cat类:


package com.chy.dp.strategy;

public class Cat {
	private int height;
	private int weight;

	public Cat(int height, int weight) {
		super();
		this.height = height;
		this.weight = weight;
	}

	public int getHeight() {
		return height;
	}

	public void setHeight(int height) {
		this.height = height;
	}

	public int getWeight() {
		return weight;
	}

	public void setWeight(int weight) {
		this.weight = weight;
	}

	@Override
	public String toString() {
		return height + "|" + weight;
	}
}

               b)那调用DataSort的Client代码:


package com.chy.dp.strategy;

public class Client {
	public static void main(String[] args) {
		// int[] a = {3,4,2,5,1};
		Cat[] a = {new Cat(1,1), new Cat(4,4), new Cat(2,2)};
		DataSort.sort(a);
		DataSort.print(a);
	}
}

               c)同样DataSort也要变:


package com.chy.dp.strategy;

public class DataSort {

	/**
	 * there many ways to sort an array, 
	 * but i just use the bubble sort to sort it.
	 * i'll use other ways to sort it if i has more time.
	 * @param a	the array will be sorted.
	 */
	public static void sort(Cat[] a) {
		for (int j = 0; j < a.length; j++) {
			for (int i = 0; i < a.length - j -1; i++) {
				if(a[i].getHeight() > a[i + 1].getHeight()){
					swap(a, i, i+1);
				}
			}
		}
	}

	/**
	 * change the two elements of an array.
	 * @param a an array.
	 * @param i	the first element index.
	 * @param j	the next element index.
	 */
	private static void swap(Cat[] a, int i, int j) {
		Cat temp = a[i];
		a[i] = a[j];
		a[j] = temp;
	}

	public static void print(Cat[] a) {
		for (int i = 0; i < a.length; i++) {
			System.out.print(a[i] + " ");
		}
	}
}


        3、给你一个狗的数组、如何调用别的类对其进行排序?


               是不是有一点点烦躁、感觉很啰嗦?在实际的需求中、我们所要面对的比这个恶心的比比皆是、我们常常说一个项目好、为什么好?标准是什么?三个词:灵活性强、可扩展性强、健壮!一个项目开发完成所需要我们coding的代码量、远远比不上我们后期维护他和扩展新功能的代码量。所以、需求不停的变动无处不在!借用一句话:A application must grow and change or it will die !

               两只狗怎么比较?给你一个标准、根据狗的饭量来比较大小

               a) 同样要比较狗、当然要有一个Dog类:


package com.chy.dp.strategy;

public class Dog {
	private int food;

	public Dog(int food) {
		super();
		this.food = food;
	}

	public int getFood() {
		return food;
	}

	public void setFood(int food) {
		this.food = food;
	}

	@Override
	public String toString(){
		return food + "";
	}
}

               b)那调用DataSort的Client代码:


package com.chy.dp.strategy;

public class Client {
	public static void main(String[] args) {
		// int[] a = {3,4,2,5,1};
		//Cat[] a = {new Cat(1,1), new Cat(4,4), new Cat(2,2)};
		Dog[] a = {new Dog(1), new Dog(5), new Dog(3)};
		DataSort.sort(a);
		DataSort.print(a);
	}
}

               c)同样DataSort也要变:


package com.chy.dp.strategy;

public class DataSort {

	/**
	 * there many ways to sort an array, 
	 * but i just use the bubble sort to sort it.
	 * i'll use other ways to sort it if i has more time.
	 * @param a	the array will be sorted.
	 */
	public static void sort(Dog[] a) {
		for (int j = 0; j < a.length; j++) {
			for (int i = 0; i < a.length - j -1; i++) {
				if(a[i].getFood()> a[i + 1].getFood()){
					swap(a, i, i+1);
				}
			}
		}
	}

	/**
	 * change the two elements of an array.
	 * @param a an array.
	 * @param i	the first element index.
	 * @param j	the next element index.
	 */
	private static void swap(Dog[] a, int i, int j) {
		Dog temp = a[i];
		a[i] = a[j];
		a[j] = temp;
	}

	public static void print(Dog[] a) {
		for (int i = 0; i < a.length; i++) {
			System.out.print(a[i] + " ");
		}
	}
}

        4、给你一个牛类你如何进行上面说的操作?


                如果下面还是创建一个牛类、修改Client、修改DataSort、然后又是一个新的东西、你会不会觉得崩溃?如果不会、那么你试试比较一下十二生肖的大小、比较完了再比较一下所有动物的大小。。。

                所以这样下去、我们就会慢慢觉得这样不禁是很蛋疼的一件事、也是一个没有一点可取之处的东西、如何优化呢?如何才能更有扩展性、才能更灵活、在DataSort中不管你是什么类、我都可以用一个方法来比较传进来的大小?想到这里、首先进入脑海的我想应该是一个接口、定义一个比较方法的接口、让所有可以比较的类实现这个接口、并且提供自己的实现。不错、这是一种优化、如何实现?

                a) 创建一个包含一个比较方法的接口、所有想要实现比较大小功能的类都要实现这个接口、并且实现自己特有的方法——Comparable代码:


package com.chy.dp.strategy;

public interface Comparable {
	/**
	 * @param the compared object.
	 * @return	if this > o return  1; 
	 * 			if this < o return -1;
	 * 			if this == o return 0; 
	 */
	public int compareTo(Object o);
}

                b) 我们简单起见、这里只使用Cat作示例、Dog可以自己尝试。Cat实现Comparable接口(注意引入自己定义的、别与java.lang.util.Comparable弄混了)、并实现自己的compareTo方法。


package com.chy.dp.strategy;

public class Cat implements Comparable{
	private int height;
	private int weight;

	public Cat(int height, int weight) {
		super();
		this.height = height;
		this.weight = weight;
	}

	public int getHeight() {
		return height;
	}

	public void setHeight(int height) {
		this.height = height;
	}

	public int getWeight() {
		return weight;
	}

	public void setWeight(int weight) {
		this.weight = weight;
	}

	@Override
	public String toString() {
		return height + "|" + weight;
	}

	@Override
	public int compareTo(Object o) {
		//如果参数都不是猫的实例、没有比较的意义、实际上这里是throw Exception、简单起见返回一个 -10
		if(!(o instanceof Cat)){
			return -10;
		}
		Cat cat = (Cat)o;
		if(this.getWeight() > cat.getWeight()){
			return 1;
		}else if ( this.getWeight() < cat.getWeight()){
			return -1;
		}else {
			return 0;
		}
	}
}

                c) DataSort方法:


package com.chy.dp.strategy;

public class DataSort {

	/**
	 * there many ways to sort an array, 
	 * but i just use the bubble sort to sort it.
	 * i'll use other ways to sort it if i has more time.
	 * @param a	the array will be sorted.
	 */
	public static void sort(Comparable[] a) {
		for (int j = 0; j < a.length; j++) {
			for (int i = 0; i < a.length - j -1; i++) {
				if(a[i].compareTo(a[i+1]) == 1){
					swap(a, i, i+1);
				}
			}
		}
	}

	/**
	 * change the two elements of an array.
	 * @param a an array.
	 * @param i	the first element index.
	 * @param j	the next element index.
	 */
	private static void swap(Comparable[] a, int i, int j) {
		Comparable temp = a[i];
		a[i] = a[j];
		a[j] = temp;
	}

	public static void print(Comparable[] a) {
		for (int i = 0; i < a.length; i++) {
			System.out.print(a[i] + " ");
		}
	}
}

                d) 这样是不是觉得爽多了、最起码我们的DataSort不再变化、不管你传进来的是什么、只要是实现Comparable接口、并且提供comparaTo方法的实现、我就可以为其进行排序!


        5、新问题:我想使用我指定的比较方式来比较Cat的大小


                我想使用猫的身高来比较、我想使用猫的体重来比较、我想使用身高加体重综合值来比较、我想使用猫的胡子的长度来比较、我想想想想。。。。这样没完没了的客户如果提出这样的要求、你会选择一直添加新类、修改代码、重复重复在重复、还是说滚出、还是寻找一种很爽的方式来解决问题?我选第三....因为要靠客户吃饭。

                a) 站在高一点的角度去思考一下:是不是我可以定义一系列的策略、或者临时添加一系列的策略、而猫可以动态的调用我们指定的策略来实现比较呢?这样我们就可以完全不用管猫内部和排序内部是怎么实现、我们只需要定义我们自己的策略就ok。比如想根据猫的身高比较、那我就定义一种根据身高比较的策略——CatHeightCompareStrategy、然后将猫的比较策略设置成它。这样不就好了?那如何实现呢?
                b) 要达到这种目的、我们就要在猫的类中添加一个所有策略的引用、因为可以指定所有策略、所以定义一个接口是无比合适的、比较器——Comparator:

package com.chy.dp.strategy;

public interface Comparator {
	//两个要比较的类
	public int comparaTo(Object o1, Object o2);
}


                c) 自己定义个比较策略、需要实现ComparaTor接口、比如根据猫的身高来比较——CatHeightCompareStrategy:


package com.chy.dp.strategy;

public class CatHeightCompareStrategy implements Comparator {
	
	@Override
	public int comparaTo(Object o1, Object o2) {
		Cat c1 = (Cat) o1;
		Cat c2 = (Cat) o2;
		if(c1.getHeight() > c2.getHeight()){
			return 1;
		}else if(c1.getHeight() < c2.getHeight()){
			return -1;
		}else{
			return 0;
		}
	}
}

                d) 让我们所想使用比较功能的类、聚合这个接口、即持有它的引用——Cat


package com.chy.dp.strategy;

public class Cat implements Comparable {
	private int height;
	private int weight;

	// 持有Comparator的实例的一个引用并且给一个默认实现、我们可以通过set方法指定
	private Comparator comparator = new CatHeightCompareStrategy();

	public Comparator getComparator() {
		return comparator;
	}

	public void setComparator(Comparator comparator) {
		this.comparator = comparator;
	}

	public Cat(int height, int weight) {
		super();
		this.height = height;
		this.weight = weight;
	}

	public int getHeight() {
		return height;
	}

	public void setHeight(int height) {
		this.height = height;
	}

	public int getWeight() {
		return weight;
	}

	public void setWeight(int weight) {
		this.weight = weight;
	}

	@Override
	public String toString() {
		return height + "|" + weight;
	}

	@Override
	public int compareTo(Object o) {
		// 如果参数都不是猫的实例、没有比较的意义、实际上这里是throw Exception、简单起见返回一个 -10
		return comparator.comparaTo(this, (Cat)o);
	}
}

                e) 测试我们的结果——Client:


package com.chy.dp.strategy;

public class Client {
	public static void main(String[] args) {
		// int[] a = {3,4,2,5,1};
		Comparable[] a = {new Cat(1,1), new Cat(4,4), new Cat(2,2)};
		DataSort.sort(a);
		DataSort.print(a);
	}
}

到此、策略模式也就告一段落了。


三:总结与补充


        1、总结:

                策略模式(StrArray Pattern)、就是动态的选择我们指定的策略来解决问题、在项目开发中、我们完全可以使用配置文件来动态的指定要使用的策略、这样灵活性、和可扩展性无疑得到了很大的提升、不必我们再痛苦的去重复的添加、修改实现方式。可以对比JDK中的实现

        2、补充:项目结构图:
                 


更多内容:Java设计模式之起始



评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值