关闭

策略模式

615人阅读 评论(0) 收藏 举报

实例场景

1、一位父亲有三个儿子,在临终签前告诉他们死后会留下的东西,分别给他们每人送了一个箱子,A儿子打开箱子需要解决一个问题能够拿到的是一栋别墅,B儿子打开箱子需要解决一个问题能够拿到的是一辆豪车,C儿子打开箱子需要解决一个问题能够拿到的是一笔巨款,在这个场景中我们用到了策略模式,下面详细说明。

2、在java的集合框架中,我们有多钟排序算法,只要用户想要哪种排序,生成相应的排序类,然后传入到Collection的sort参数中,就能够实现相应的排序规则,这里面用到了我们的策略模式。

策略模式

策略模式,又叫算法簇模式,就是定义了不同的算法族,并且之间可以互相替换,此模式让算法的变化独立于使用算法的客户。

策略模式的好处在于你可以动态的改变对象的行为。

设计原则

     设计原则是把一个类中经常改变或者将来可能改变的部分提取出来,作为一个接口(c++z中可以用虚类),然后在类中包含这个对象的实例,这样类的实例在运行时就可以随意调用实现了这个接口的类的行为。下面是一个例子。 策略模式属于对象行为型模式,主要针对一组算法,将每一个算法封装到具有共同接口的独立的类中,从而使得它们可以相互替换。策略模式使得算法可以在不影响到客户端的情况下发生变化。通常,策略模式适用于当一个应用程序需要实现一种特定的服务或者功能,而且该程序有多种实现方式时使用。

策略模式中有三个对象
(1)       环境对象:该类中实现了对抽象策略中定义的接口或者抽象类的引用。
(2)       抽象策略对象:它可由接口或抽象类来实现。
(3)       具体策略对象:它封装了实现同不功能的不同算法。
利用策略模式构建应用程序,可以根据用户配置等内容,选择不同有算法来实现应用程序的功能。具体的选择有环境对象来完成。采用这种方式可以避免由于使用条件语句而带来的代码混乱,提高应用程序的灵活性与条理性。

代码实现场景:

模拟场景1

package cn.com.strategy;
//定义一个策略接口,这是父亲给三个儿子设计问题取得遗产的接口
public interface IStrategy {
	//打开箱子,每个问题都是一个算法
	public void execute();
}

package cn.com.strategy;
//定义一个实现类,A儿子打开箱子,解决问题,得到一栋别墅
public class ImplA implements IStrategy {
	@Override
	public void execute() {
		System.out.println("解决问题,得到一栋别墅");

	}

}

package cn.com.strategy;
//定义一个实现类,B儿子打开箱子,解决问题,得到一栋豪车
public class ImplB implements IStrategy {
	@Override
	public void execute() {
		System.out.println("解决问题,得到一辆豪车");
	}

}
package cn.com.strategy;
//定义一个实现类,C儿子打开箱子,解决问题,得到一笔巨款
public class ImplC implements IStrategy {
	@Override
	public void execute() {
		System.out.println("解决问题,得到一笔巨款");

	}

}
package cn.com.strategy;
//定义一个环境对象,在场景中就像那个箱子
public class Environment {
	private IStrategy iStrategy;
	//两种方法为其赋值,构造和set、get
	public Environment(IStrategy iStrategy){
		this.iStrategy=iStrategy;
	}
	
	public void execute(){
		iStrategy.execute();
	}
	
}

package cn.com.strategy;
//测试类,看似代码一样,但是传入不同的实现类,得到不同结果
public class Test {
	public static void main(String[] args) {
		Environment e=new Environment(new ImplA());
		e.execute();//A儿子打开箱子解决问题,得到一栋别墅
		e=new Environment(new ImplB());
		e.execute();//B儿子打开箱子解决问题,得到一辆豪车
		e=new Environment(new ImplC());
		e.execute();//C儿子打开箱子解决问题,得到一笔巨款
	}

}

输出结果将会是:

解决问题,得到一栋别墅 
解决问题,得到一辆豪车
解决问题,得到一笔巨款


模拟场景2:自定义排序算法

package cn.com.strategy;

import java.util.List;
//定义一个排序的策略接口
public interface SortStrategy<T> {
	public void sort(List<T> list);//执行排序算法
}


package cn.com.strategy;

import java.util.List;

//定义一个实现类,实现冒泡排序
public class SortBubble<T> implements SortStrategy<T> {
	@Override
	public void sort(List<T> list) {
		System.out.println("实现冒泡排序算法");
	}

}


package cn.com.strategy;

import java.util.List;

//定义一个实现类,实现堆排序
public class SortHeap<T> implements SortStrategy<T> {
	@Override
	public void sort(List<T> list) {
		System.out.println("实现堆排序算法");
	}
}


package cn.com.strategy;

import java.util.List;

//定义一个实现类,实现快速排序
public class SortQuick<T> implements SortStrategy<T> {
	@Override
	public void sort(List<T> list) {
		System.out.println("实现快速排序算法");
	}

}


package cn.com.strategy;

import java.util.List;

//定义一个环境对象,在场景中就是我们的算法使用者
public class Sorter {
	private SortStrategy iStrategy;
	//两种方法为其赋值,构造和set、get
	public SortStrategy getiStrategy() {
		return iStrategy;
	}

	public void setiStrategy(SortStrategy iStrategy) {
		this.iStrategy = iStrategy;
	}
	//传入相应的算法,对其进行排序
	public void sort(List list){
		this.iStrategy.sort(list);
	}
	
}


package cn.com.strategy;

import java.util.ArrayList;
import java.util.List;

//测试类,看似代码一样,但是传入不同的排序实现类,得到不同的排序结果
public class Test {
	public static void main(String[] args) {
		List list=new ArrayList();
		list.add(2);
		list.add(3);
		list.add(1);
		Sorter sort=new Sorter();
		SortBubble<Integer> sb=new SortBubble<Integer>();
		sort.setiStrategy(sb);//实现冒泡排序
		sort.setiStrategy(new SortHeap<Integer>());//实现堆排序
		sort.setiStrategy(new SortQuick<Integer>());//实现快速排序
		
	}

}

输出相应的排序结果
在我们的集合框架中可以设计不同的Comparator来实现不同的比较方式,大大的提高了程序的扩展性,但值得说的类也要实现Comparable接口,只是在Comparable接口的实现方法中使用我们自己设置的排序策略,当然我们可以指定默认的排序算法,如上,这样如果有特殊需求时,在设置相应的排序算法,极大的提高了系统的灵活性。


策略模式优缺点

优点:

1、 简化了单元测试,因为每个算法都有自己的类,可以通过自己的接口单独测试。
2、 避免程序中使用多重条件转移语句,使系统更灵活,并易于扩展。
3、 遵守大部分GRASP原则和常用设计原则,高内聚、低偶合。

缺点:
1、 因为每个具体策略类都会产生一个新类,所以会增加系统需要维护的类的数量。

2、 在基本的策略模式中,选择所用具体实现的职责由客户端对象承担,并转给策略模式的Context对象。(这本身没有解除客户端需要选择判断的压力,而策略模式与简单工厂模式结合后,选择具体实现的职责也可以由Context来承担,这就最大化的减轻了客户端的压力。)

简单工厂模式和策略模式区别(摘录,出处)

这两种模式的作用就是拥抱变化,减少耦合。在变化来临时争取做最小的改动来适应变化。这就要求我们把些“善变”的功能从客户端分离出来,形成一个个的功能类,然后根据多态特性,使得功能类变化的同时,客户端代码不发生变化。

简单工厂模式

简单工厂模式:有一个父类需要做一个运算(其中包含了不同种类的几种运算),将父类涉及此运算的方法都设成虚方法,然后父类派生一些子类,使得每一种不同的运算都对应一个子类。另外有一个工厂类,这个类一般只有一个方法(工厂的生成方法),这个方法的返回值是一个超类,在方法的内部,根据传入参数的不同,分别构造各个不同的子类的对象,并返回。客户端并不认识子类,客户端只认识超类和工厂类。每次客户端需要一中运算时,就把相应的参数传给工厂类,让工厂类构造出相应的子类,然后在客户端用父类接收(这里有一个多态的运用)。客户端很顺理成章地用父类的计算方法(其实这是一个虚方法,并且已经被子类特化过了,其实是调用子类的方法)计算出来结果。如果要增加功能时,你只要再从父类中派生相应功能的子类,然后修改下工厂类就OK了,对于客户端是透明的。

策略模式

策略模式:策略模式更直接了一点,没有用工厂类,而是直接把工厂类的生成方法的代码写到了客户端。客户端自己构造出了具有不同功能的子类(而且是用父类接收的,多态),省掉了工厂类。策略模式定义了算法家族,分别封装起来,让他们之间可以互相替换,此模式让算法的变化,不会影响到使用算法的客户。这里的算法家族和简单工厂模式里的父类是同一个概念。当不同的行为堆砌在一个类中时,就很难避免使用条件语句来选择合适的行为,将这些行为封装在一个个独立的策略子类中,可以在客户端中消除条件语句。

简单工厂模式+策略模式:为了将工厂方法的代码从客户端移出来,我们把这些代码搬到了父类的构造函数中,让父类在构造的时候,根据参数,自己实现工厂类的作用。这样做的好处就是,在客户端不用再认识工厂类了,客户端只要知道父类一个就OK,进一步隔离了变化,降低了耦合。

在基本的策略模式中,选择所用具体实现的职责由客户端对象成端,并转给客户端。这本身并没有减除客户端需要选择判断的压力,而策略模式与简单工厂模式结合后,选择具体实现的职责也可以由父类承担,这就最大化地减轻了客户端的职责。

总结

策略模式作为一种软件设计模式,指对象有某个行为,但是在不同的场景中,该行为有不同的实现算法。

0
0

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:421536次
    • 积分:5863
    • 等级:
    • 排名:第4329名
    • 原创:215篇
    • 转载:39篇
    • 译文:3篇
    • 评论:113条
    最新评论