策略模式

策略模式的使用情景:

有一系列平行的解决某一问题的算法,为这些算法抽象出一个接口,所有算法都是该接口的具体实现。实现一个上下文(Context),在上下文中有算法接口的引用。使用算法的客户不直接使用具体算法类,而是和上下文交互,这样实现了客户端和算法的解耦。


假设现在有这样的需求:商家对新客户的报价是原价,老客户打9折,大客户打8.5折。简单的实现可以用多个 if else 判断,但当增加新的定价方案时不容易扩展,需要修改现有代码。这种情况下,使用策略模式较合适。


示例代码

public class Strategy_Model {
	public static void main(String[] args) {
		NewCustomerStrategy ns = new NewCustomerStrategy();
		Price p = new Price(ns);
		p.quote(100);
		
		OldCustomerStrategy os = new OldCustomerStrategy();
		Price p2 = new Price(os);
		p2.quote(100);
		
		BigCustomerStrategy bs = new BigCustomerStrategy();
		Price p3 = new Price(bs);
		p3.quote(100);
	}
}

class Price {
	private Strategy strategy;

	public Price(Strategy strategy){
		this.strategy = strategy;
	}
	
	public void quote(double goodPrice){
		this.strategy.calculatePrice(goodPrice);
	}
}

interface Strategy{
	public void calculatePrice(double goodPrice);
}
class NewCustomerStrategy implements Strategy{

	@Override
	public void calculatePrice(double goodPrice) {
		// TODO Auto-generated method stub
		System.out.println("新客户原价");
	}
	
}
class OldCustomerStrategy implements Strategy{
	
	@Override
	public void calculatePrice(double goodPrice) {
		// TODO Auto-generated method stub
		System.out.println("老客户9折 "+goodPrice*0.9);
	}
	
}
class BigCustomerStrategy implements Strategy{
	
	@Override
	public void calculatePrice(double goodPrice) {
		// TODO Auto-generated method stub
		System.out.println("大客户8.5折 "+goodPrice*0.85);
		
	}
	
}

策略模式将具体的算法从业务中独立出来,形成一系列单独的算法类,算法类间可以替换,策略模式的重心不是如何实现算法,而是如何组织、调用这些算法,从而让程序结构更灵活,可维护可扩展。


具体策略的选择,选择权在客户端。上下文(比如上例中的Price类)是客户端和具体策略间的媒介。


策略的实现,一般就像上例抽象一个策略的接口,然后实现不同的策略实现类。如果有公共功能需要实现,那就把接口改成抽象类,公共功能在抽象类中实现。


Strategy 和 Context 的关系:Context中有Strategy的引用,Strategy也可以从Context中获取数据,将Context对象作为参数传递给Strategy,Strategy回调Context的方法获取数据,这种情况下,Context可以作为Strategy的公共功能的实现类。


假设现在有这样的需求:有不同的工资结算方式,比如,美元,人民币,银行转账。下面用策略模式,将上下文对象传递给策略实现对象的方式实现。


示例代码:

public class Strategy_Salary_Model {
	public static void main(String[] args) {
		SalaryStrategy rmb = new RMBStrategy();
		Salary s1 = new Salary("小张", 12000, rmb);
		s1.paySalary();
		
		SalaryStrategy dollar = new DollarStrtegy();
		Salary s2 = new Salary("Jim", 8000, dollar);
		s2.paySalary();
	}
}

interface SalaryStrategy{
	public void pay(Salary s);
}

class Salary{
	private SalaryStrategy strategy;
	private double salary;
	private String userName;
	
	

	public SalaryStrategy getStrategy() {
		return strategy;
	}

	public double getSalary() {
		return salary;
	}

	public String getUserName() {
		return userName;
	}

	public Salary(String userName,double salary,SalaryStrategy strategy){
		this.userName = userName;
		this.salary = salary;
		this.strategy = strategy;
	}
	
	public void paySalary(){
		this.strategy.pay(this);
	}
}

class RMBStrategy implements SalaryStrategy{

	@Override
	public void pay(Salary s) {
		// TODO Auto-generated method stub
		System.out.println("付给 "+s.getUserName()+" RMB "+s.getSalary());
	}
	
}
class DollarStrtegy implements SalaryStrategy{

	@Override
	public void pay(Salary s) {
		// TODO Auto-generated method stub
		System.out.println("付给 "+s.getUserName()+" Dollar "+s.getSalary());
		
	}
	
}

结果:

付给 小张 RMB 12000.0
付给 Jim Dollar 8000.0

假设现在要扩展一张支付方式:银行转账。因为需要银行账号,故重写一个上下文SalaryBank继承Salary.添加一个新的银行转账的策略。

class SallaryBank extends Salary{

	private int account;
	
	

	public int getAccount() {
		return account;
	}



	public SallaryBank(String userName, double salary,int bankAccount, SalaryStrategy strategy) {
		super(userName, salary, strategy);
		this.account = bankAccount;
	}
	
}

class BankStrtegy implements SalaryStrategy{

	@Override
	public void pay(Salary s) {
		// TODO Auto-generated method stub
		System.out.println("付给 "+s.getUserName()+" "+s.getSalary()+",通过银行转账,账户:"+((SallaryBank)s).getAccount());

	}
	
}

public class Strategy_Salary_Model {
	public static void main(String[] args) {
		SalaryStrategy rmb = new RMBStrategy();
		Salary s1 = new Salary("小张", 12000, rmb);
		s1.paySalary();
		
		SalaryStrategy dollar = new DollarStrtegy();
		Salary s2 = new Salary("Jim", 8000, dollar);
		s2.paySalary();
		
		SalaryStrategy bank = new BankStrtegy();
		SallaryBank s3 = new SallaryBank("王经理", 8000, 123456,bank);
		s3.paySalary();
		
		
	}
}

结果:

付给 小张 RMB 12000.0
付给 Jim Dollar 8000.0
付给 王经理 8000.0,通过银行转账,账户:123456

上面的例子通过改变上下文,通过上下文来获取数据。还可以直接修改策略,通过具体策略实现类的构造函数传参。

class BankStrategy2 implements SalaryStrategy{
	
	private int account;

	public BankStrategy2(int account){
		this.account = account;
	}

	@Override
	public void pay(Salary s) {
		// TODO Auto-generated method stub
		
		System.out.println("付给 "+s.getUserName()+" "+s.getSalary()+",通过银行转账,账户:"+this.account);
	}
	
}


		SalaryStrategy bank = new BankStrategy2(789456);
		Salary s3 = new Salary("王经理", 10000,bank);
		s3.paySalary();

运行结果:

付给 王经理 10000.0,通过银行转账,账户:789456

两种方式,看情况选用。


对应策略算法在实现上有公共功能的情况,实现方式有:

1),将接口写成抽象类,把公共功能在抽象类中实现。

2),将公共功能放在Context里实现,具体策略对象回调上下文对象。

3),为所有策略算法抽象一个父类,该父类去实现策略接口,在该父类中实现公共功能。


策略模式的本质“分离算法,选择实现” 。




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值