策略模式

什么是策略模式?

策略模式(Strategy)顾名思义,就是应对一个事情要有不同的策略。
不同的策略中对应不同的方法去应对。例如诸葛亮给赵云的锦囊妙计。根据诸葛亮推测它老大哥的处境,给出不同的策略去执行。
这就是策略模式。

策略模式(Strategy Pattern)是一种比较简单的模式,也叫做政策模式(Policy Pattern)。其定义如下: Define a family of algorithms,encapsulate each one,and make them interchangeable.(定义一组 算法,将每个算法都封装起来,并且使它们之间可以互换。)
— 《设计模式之禅》

设计模式框架图:
在这里插入图片描述
策略模式使用的就是面向对象的继承和多态机制,非常容易理解和掌握,我们再来看看 策略模式的三个角色
● Context封装角色
它也叫做上下文角色,起承上启下封装作用,屏蔽高层模块对策略、算法的直接访问, 封装可能存在的变化。

● Strategy抽象策略角色 策略、算法家族的抽象,通常为接口,定义每个策略或算法必须具有的方法和属性。各位看官可能要问了,类图中的AlgorithmInterface是什么意思,嘿嘿,algorithm是“运算法则”的 意思,结合起来意思就明白了吧。

● ConcreteStrategy具体策略角色 实现抽象策略中的操作,该类含有具体的算法。 我们再来看策略模式的通用源码,非常简单。先看抽象策略角色,它是一个非常普通的 接口,在我们的项目中就是一个普通得不能再普通的接口了,定义一个或多个具体的算法。

下面给大家举两个例子,相信大家就会很容易理解。

诸葛亮的锦囊妙计

这个例子摘自《设计模式之禅》

在诸葛亮气周瑜的过程中,有一件事情:那就是周瑜赔了夫人又折兵这件事情。事情经过是这样的:孙权看刘备有雄起之意,杀是不能杀了,那会惹天下人唾弃,就想个招儿挫他一下,那有什么办法呢?孙权有个妹妹——孙尚香,准备招刘备做女婿,然后孙权想办法把刘备软禁起来,孙权的想法还是很单纯的嘛,就是不让你刘备回西川,然后我东吴想干啥就干啥,夺荆州,吞西川也不是不可能的。东吴的想法是好的,无奈中间多了智谋无敌的诸葛亮,他早就预测了东吴有此招数,于是在刘备去东吴招亲之前,特授以伴郎赵云三个锦囊,说是按天机拆开解决棘手问题。

这三个妙计分别是:找乔国老帮忙(也就是走后门了),求吴国太放行(诉苦)以及孙夫人断后,对这三个妙计不熟悉的读者可以去温习一下《三国演义》,这里就不多说了。想想看,这三个计谋有什么相似之处,他们都是告诉赵云要怎么执行,也就是说这三个计谋都有一个方法是执行,具体执行什么内容,每个计谋当然不同了,分析到这里,我们是不是就有这样一个设计思路:三个妙计应该实现的是同一个接口?聪明!是的,我们来看类图,如图18-1所示。

在这里插入图片描述
那么在代码中我们该如何去设计呢?

首先我们把妙计设计为接口

public interface IStrategy { 
//每个锦囊妙计都是一个可执行的算法 
public void operate(); 
}

接口很简单,定义了一个方法operate,每个妙计都是可执行的,否则那叫什么妙计,我 们先看第一个妙计——找乔国老开后门

public class BackDoor implements IStrategy { 
	public void operate() { 
		System.out.println("找乔国老帮忙,让吴国太给孙权施加压力"); }
}

第二个妙计是找吴国太哭诉,企图给自己开绿灯

public class GivenGreenLight implements IStrategy{
	public void operate(){
		System.out.println("求吴国太开绿灯,放行!")
	}
}

第三个妙计是在逃跑的时候,让新娘子孙夫人断后,谁来砍谁。

public class BlockEnemy implements IStrategy { 
	public void operate() { 
		System.out.println("孙夫人断后,挡住追兵"); 
	} 
}

在这个场景中,三个妙计都有了,那还缺少两个配角

第一,妙计肯定要放到一个地方 吧,这么重要的东西要保管呀,也就是承装妙计的锦囊,所以俗称锦囊妙计嘛;

第二,这些 妙计都要有一个执行人吧,是谁?当然是赵云了,妙计是小亮给的,执行者是赵云。赵云就 是一个干活的人,从锦囊中取出妙计,执行,然后获胜。过程非常清晰,我们把完整的过程 设计出来

在这里插入图片描述

public class Context { 	
	//妙计
	private IStrategy istrategy ;
	//构造函数来给妙计具体的参数
	Context(IStrategy istrategy){
		this.istrategy = istrategy;
	}
	//使用该妙计
	public void operate(){
		this.istrategy.operate();
	}
 }

通过构造函数把策略传递进来,然后用operate()方法来执行相关的策略方法。三个妙计 有了,锦囊也有了,然后就是赵云雄赳赳地揣着三个锦囊,拉着已步入老年行列的、还想着娶纯情少女的刘老爷子去入赘了。嗨,还别说,小亮同志的三个妙计还真是不错,

public class ZhaoYun { 
	//赵云出场了,他根据诸葛亮给他的交代,依次拆开妙计 
	public static void main(String[] args) {
		Context context; 
		//刚刚到吴国的时候拆第一个
		System.out.println("---刚刚到吴国的时候拆第一个---"); 
		//拿到妙计 
		context = new Context(new BackDoor()); 
		//拆开执行 
		context.operate(); 
	
		System.out.println("\n\n\n\n\n\n\n\n"); 
		
		//刘备乐不思蜀了,拆第二个了 
		System.out.println("---刘备乐不思蜀了,拆第二个了---"); 
		context = new Context(new GivenGreenLight()); 		
		//执行了第二个锦囊    
		context.operate(); 
		
		System.out.println("\n\n\n\n\n\n\n\n");
		
	 	//孙权的小兵追来了,咋办?拆第三个 
	 	System.out.println("---孙权的小兵追来了,咋办?拆第三个---");
	  	context = new Context(new BlockEnemy());
	  	 //孙夫人退兵 
	  	 context.operate(); 
	  	
	  	System.out.println("\n\n\n\n\n\n\n\n"); 
  } 
}

这整个过程就是一个策略模式。

ComparaTor

在之前的博客中我写过ComparaTor,实际应用也很简单,对类的比较而言有不同的比较方法,只需要在具体实现时实现ComparaTor接口,这样就可以实现多维度的比较了。

我们来定义 猫 类。
在这里们对猫进行排序,根据猫的不同属性进行排序,我们就要实现Comparator接口。

UML图:
在这里插入图片描述

class Cat{
    private int heigh ;
    private int weight;

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

    public void setHeigh(int heigh) {
        this.heigh = heigh;
    }

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

    public int getHeigh() {
        return heigh;
    }

    public int getWeight() {
        return weight;
    }

    @Override
    public String toString() {
        return "Cat{" +
                "heigh=" + heigh +
                ", weight=" + weight +
                '}';
    }
}

排序工具类

class SortUtil<E>{

    public void Sort(E[] arr, Comparator<E> comparator){
        //写个简单的快排
         quicksort(arr,0,arr.length-1,comparator);
    }

    private void quicksort(E[] arr,int left,int right,Comparator<E> comparator){
        if(left > right) return;

        int parartion = getParation(arr,left,right,comparator);
        if(parartion - left > 1){
            quicksort(arr,left,parartion-1,comparator);
        }
        if(right - parartion > 1){
            quicksort(arr,parartion+1,right,comparator);
        }
    }
    private int getParation(E[] arr,int left,int right,Comparator<E> comparator){
        E porvit = arr[left];
        while(left <= right ){
            //从后向前找 右边为大于等于
            while( left < right && comparator.compare(arr[right],porvit) >= 0 ){
                    right--;
            }
            //直接放置
            arr[left] = arr[right];
            //从前向后找 左边为小于
            while(left < right && comparator.compare(arr[left],porvit) < 0 ){
                    left++;
            }
            arr[right] = arr[left];
            if(left == right){
                break;
            }
        }
        arr[left] = porvit;
        return left;
    }
}

两个排序准则,实现的两个比较器

class CatHighComparator implements  Comparator<Cat>{
        @Override
    public int compare(Cat o1, Cat o2) {
        if(o1.getHeigh() > o2.getHeigh()) return 1;
        else if( o1.getHeigh() < o2.getHeigh()) return -1;
        return 0;
    }
}

class CatWeightComparator implements Comparator<Cat>{
    @Override
    public int compare(Cat o1, Cat o2) {
        if(o1.getWeight() > o2.getWeight()) return 1;
        else if(o1.getWeight() < o2.getWeight()) return -1;
        return 0;
    }
}

测试

public static void main(String[] args) {
        Cat[] arr = {new Cat(1,3),new Cat(2,4),new Cat(4,1)};
        SortUtil sortUtil = new SortUtil();
        sortUtil.Sort(arr,new CatHighComparator());
        System.out.println(Arrays.toString(arr));
        sortUtil.Sort(arr,new CatWeightComparator());
        System.out.println(Arrays.toString(arr));

    }

结果:
在这里插入图片描述
第一行,按照heigh 排序, 第二行按照weight 排序。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值