我的设计模式(二):Strategy 策略模式

一、概述

     在策略模式(Strategy Pattern)中,一个类的行为或其算法可以在运行时更改。这种类型的设计模式属于行为型模式。 那么我们就由实际需求出发,一步一步深入剖析设计原理。

二、解析

    1. int数组排序

    我们假设一种业务场景,要对一个int数组进行排序,测试类代码如下:

import java.util.Arrays;

public class Main {
	
	public static void main(String[] args) {
		int[] a = {9,2,3,5,7,1,4};
		Sorter sorter = new Sorter();
		sorter.sort(a);
		System.out.println(Arrays.toString(a));
	}
}

    其中的排序类Sorter源码如下:

public class Sorter {

	public static void sort(int[] arr) {
		for (int i = 0; i < arr.length - 1; i++) {
			int minPos = i;
			for (int j = i+1; j < arr.length; j++) {
				minPos = arr[j] < arr[minPos] ? j : minPos;
			}
			swap(arr, i, minPos);
		}
	}

	static void swap(int[] arr, int i, int j) {
		int temp = arr[i];
		arr[i] = arr[j];
		arr[j] = temp;
	}
}

    测试结果如下图:

up-71612325bd895916f08ae7d8bd2b77a0c96.png

    如上图所示,完美实现了排序,这是我们所预期的结果。那么在此基础上,如果我们不仅想对int类型的数组进行排序,还想对double,String甚至是自定义的类Cat等数组进行排序,那么我们就需要修改Sorter类的sort()方法的具体实现。

    2. 自定义Cat类数组排序

    以Cat类为研究对象,那么我们怎么知道哪只猫大哪只猫小呢?这就需要我们自己定义好比较的规则,Cat类源码如下:

public class Cat {
	int weight, height;

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

	//自定义的比较规则
	public int compareTo(Cat c) {
		if (this.weight < c.weight)
			return -1;
		else if (this.weight > c.weight)
			return 1;
		else
			return 0;
	}

	@Override
	public String toString() {
		return "Cat [weight=" + weight + ", height=" + height + "]";
	}
}

    我们要对Cat数组进行排序,那么就需要修改Sorter类的sort()方法,修改后的源码如下:

import java.util.Arrays;

public class Main {
	
	public static void main(String[] args) {
		Cat[] a = {new Cat(3,3),new Cat(5,5),new Cat(1,1)};
		Sorter sorter = new Sorter();
		sorter.sort(a);
		System.out.println(Arrays.toString(a));
	}
}

    输出结果如下:

up-605686928c222954f0b2096ea0b04e2f3d6.png

    3. 对任何类数组进行排序-泛型

    如果想对其他自定义类进行排序,总不能每次都修改Sorter类的sort()方法,那么我们可以定义一个MyComparable接口,MyComparable接口中有一个比较方法compareTo(),每个类实现这个MyComparable接口并且实现自己的compareTo()方法来完成自己的比较规则。

    MyComparable接口源码如下:

public interface MyComparable<T> {

	int compareTo(T t);
}

    Cat实现MyComparable接口后的源码如下:

public class Cat implements MyComparable<Cat>{
	int weight, height;

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

	//自定义的比较规则
	public int compareTo(Cat c) {
		if (this.weight < c.weight)
			return -1;
		else if (this.weight > c.weight)
			return 1;
		else
			return 0;
	}

	@Override
	public String toString() {
		return "Cat [weight=" + weight + ", height=" + height + "]";
	}
}

    这样只需要让Sorter类的sort()方法针对MyComparable类型的数组进行排序,这样所有实现MyComparable接口的类都可以用自己的排序规则进行排序,Sorter类源码如下:

public class Sorter {

	public static void sort(MyComparable[] arr) {
		for (int i = 0; i < arr.length - 1; i++) {
			int minPos = i;
			for (int j = i+1; j < arr.length; j++) {
				minPos = arr[j].compareTo(arr[minPos])==-1 ? j : minPos;
			}
			swap(arr, i, minPos);
		}
	}

	static void swap(MyComparable[] arr, int i, int j) {
		MyComparable temp = arr[i];
		arr[i] = arr[j];
		arr[j] = temp;
	}
}

    运行测试代码结果与上面一致,如下:

up-605686928c222954f0b2096ea0b04e2f3d6.png

    到这里,我们貌似已经解决了我们针对不同的类也能调用一个sort()方法就能够排序,但是还是有问题,现在Cat类是利用weight字段来进行比较的,如果Cat类想要换一种比较策略用height呢?显然现在的代码是无法满足的,因为Cat类只有一个compareTo()方法,只能完成一种排序规则,所以这个时候就轮到我们的策略模式登场啦!

    4. Comparator-灵活指定比较策略

    设计模式中我们要求满足开闭原则,对修改关闭,对拓展开放。所以我们针对不同的比较策略不能去修改Cat类的compareTo()方法,处于这样的考虑,我们可以先创建一个比较器接口Comparator,里面有一个比较方法compareTo(),源码如下:

public interface MyComparator<T> {

	int compareTo(T o1,T o2);
}

    根据不同的比较策略创建不同的子比较器CatComparator类,源码如下:

public class CatComparator implements MyComparator<Cat>{

	@Override
	public int compareTo(Cat o1, Cat o2) {
		if (o1.weight < o2.weight)
			return -1;
		else if (o1.weight > o2.weight)
			return 1;
		else
			return 0;
	}

}

    Sorter类也做出修改,源码如下:

public class Sorter {

	public void sort(Cat[] arr,MyComparator<Cat> Comparator) {
		for (int i = 0; i < arr.length - 1; i++) {
			int minPos = i;
			for (int j = i+1; j < arr.length; j++) {
				minPos = Comparator.compareTo(arr[j],arr[minPos])==-1 ? j : minPos;
			}
			swap(arr, i, minPos);
		}
	}

    void swap(Cat[] arr, int i, int j) {
    	Cat temp = arr[i];
		arr[i] = arr[j];
		arr[j] = temp;
	}
}

    测试代码如下:

import java.util.Arrays;

public class Main {
	
	public static void main(String[] args) {
		Cat[] a = {new Cat(3,3),new Cat(5,5),new Cat(1,1)};
		Sorter sorter = new Sorter();
		sorter.sort(a,new CatComparator());
		System.out.println(Arrays.toString(a));
	}
}

    测试结果如下图:

up-605686928c222954f0b2096ea0b04e2f3d6.png

    由结果我们可以看出,代码是正确的完成了排序,那么我们针对其他的比较策略,还可以创建子比较器CatHeightComparator类,源码如下:

public class CatHeightComparator implements MyComparator<Cat>{

	@Override
	public int compareTo(Cat o1, Cat o2) {
		if (o1.height > o2.height)
			return -1;
		else if (o1.height < o2.height)
			return 1;
		else
			return 0;
	}

}

    我们只需要在调用排序方法时,传入比较器CatHeightComparator的实例,就可以完成第二种排序策略,测试代码如下:

import java.util.Arrays;

public class Main {
	
	public static void main(String[] args) {
		Cat[] a = {new Cat(3,3),new Cat(5,5),new Cat(1,1)};
		Sorter sorter = new Sorter();
		sorter.sort(a,new CatHeightComparator());
		System.out.println(Arrays.toString(a));
	}
}

    测试结果符合预期,如下:

    至此,我们利用策略模式完成了所有的设想!

三、总结

    总的来说,策略模式就是定义一个策略框架,每次需要用特定的策略时,我们就实现具体的规则,以此来实现策略的多变切换以达到代码的健壮性。

    更多精彩内容,敬请扫描下方二维码,关注我的微信公众号【Java觉浅】,获取第一时间更新哦!

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Java觉浅

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值