【设计模式】策略模式的实现--------java

23 篇文章 0 订阅
22 篇文章 0 订阅

策略模式(Strategy Pattern)

什么时候用策略模式:一个系统需要动态地在几种算法中方选择一种时。

1.银行收银软件(由单价、数量,向客户收费)

package computer;

import java.util.Scanner;

public class Test {
	public static void main(String[] args) {
		Cash cash = new Cash();
		boolean flag = true;
		while (flag) {
			cash.buttonOK();
			if (cash.totalPrice > 10) {
				flag = false;
			}
		}
		System.out.println("=======================================");
		System.out.print("购物清单:" + "\n"+cash.list);
		System.out.println("总价:" + cash.totalPrice);
	}

}

class Cash {
	public String list = "";
	public double totalPrice = 0.00;

	public void buttonOK() {
		Scanner cin = new Scanner(System.in);
		System.out.print("请输入单价:");
		String price = cin.next();
		System.out.print("请输入数量:");
		String num = cin.next();
		double xiaoji = Double.parseDouble(price) * Integer.parseInt(num);
		// 清单
		list += "单价:" + price + ",数量:" + num + ",小计" + xiaoji + "\n";
		// 将每个小计计入总计
		totalPrice += xiaoji;
	}
}

问题:商场搞活动折扣不断变化,则程序也不断变化。
改进:输入折扣。

2.改进:(输入折扣)

package computer;

import java.util.Scanner;

public class Test {
	public static void main(String[] args) {
		Cash cash = new Cash();
		boolean flag = true;
		while (flag) {
			cash.buttonOK();
			if (cash.totalPrice > 10) {
				flag = false;
			}
		}
		System.out.println("=======================================");
		System.out.print("购物清单:" + "\n" + cash.list);
		System.out.println("总价:" + cash.totalPrice);
	}

}

class Cash {
	public String list = "";
	public double totalPrice = 0.00;

	public void buttonOK() {
		Scanner cin = new Scanner(System.in);
		System.out.print("请输入单价:");
		String price = cin.next();

		System.out.print("请输入数量:");
		String num = cin.next();

		System.out.print("请输入所享折扣:");
		String zhekou = cin.next();

		double xiaoji = Double.parseDouble(price) * Integer.parseInt(num) * Double.parseDouble(zhekou);
		// 清单
		list += "单价:" + price + ",数量:" + num + ",折扣" + zhekou + ",小计" + xiaoji + "\n";
		// 将每个小计计入总计
		totalPrice += xiaoji;
	}
}

缺点:在添加满300减100的促销算法等程序会变得复杂。

3.改进:(用简单工厂模式)
一个父类 多个子类分别为打折子类、返利子类…再加工厂类
在这里插入图片描述

package computer;

import java.util.Scanner;

public class Test {
	public static void main(String[] args) {
		Scanner cin=new Scanner(System.in);
		boolean flag=true;
		String list="";
		double totalPrice=0.00;
		
		while(flag) {
			System.out.print("请输入单价:");
			String price=cin.next();
			
			System.out.print("请输入数量:");
			String num=cin.next();
			
			System.out.print("请输入折扣类型(1无折扣 2打折 3 满减):");
			String type=cin.next();
			
			double discount=0;
			double basePrice=0;
			double returnPrice=0;
			
			if(type.equals("2")) {
				System.out.print("请输入折扣:");
				discount=Double.parseDouble(cin.next());
			}
			
			if(type.equals("3")) {
				System.out.print("请输入返现基础金额:");
				basePrice=Double.parseDouble(cin.next());
				System.out.print("请输入返现金额:");
				returnPrice=Double.parseDouble(cin.next());
			}
			//单价*金额
			double xiaoji=Double.parseDouble(price)*Double.parseDouble(num);
			
			CashSuper cs=CashAcceptFactory.createCashAccept(type, discount, basePrice, returnPrice);
			//处理后的价格
			xiaoji=cs.acceptCash(xiaoji);
			list+="单价"+price+",数量"+num+",折扣"+discount+",小计"+xiaoji+"\n";
			totalPrice+=xiaoji;
			
			if(totalPrice>10) {
				flag=false;
			}
		}
		
		System.out.println("=====================================================");
		System.out.print("清单:\n"+list);
		System.out.println("总价:"+totalPrice);
	}

}

//抽象现金收取类
abstract class CashSuper{
	//抽象方法(参数为原价,返回当前价)
	public abstract double acceptCash(double money);
}

//正常收费类
class CashNormal extends CashSuper{
	public double acceptCash(double money) {
		return money;
	}
}

//打折收费类
class CashRebate extends CashSuper{
	private double discount=0.00;
	public CashRebate(double discount){
		this.discount=discount;
	}
	
	//继承的方法
	public double acceptCash(double money) {
		return money*discount;
	}

	public double getDiscount() {
		return discount;
	}
	public void setDiscount(double discount) {
		this.discount = discount;
	}
	
}

//返利收费类
class CashReturn extends CashSuper{
	//基础金额
	private double baseCash;
	//返现金额
	private double returnCash;

	//构造设置基础金额和返现金额
	public CashReturn(double baseCash, double returnCash) {
		this.baseCash = baseCash;
		this.returnCash = returnCash;
	}
	
	//继承的方法
	public double acceptCash(double money) {
		double result=money;
		if(money>baseCash) {
			result=money-Math.floor(money/baseCash)*returnCash;
		}
		return result;
	}

	public double getBaseCash() {
		return baseCash;
	}

	public void setBaseCash(double baseCash) {
		this.baseCash = baseCash;
	}

	public double getReturnCash() {
		return returnCash;
	}

	public void setReturnCash(double returnCash) {
		this.returnCash = returnCash;
	}
	
}

//现金收取工厂
class CashAcceptFactory{
	//根据参数生成相应的对象(类型,折扣,基础金额,返现金额)
	public static CashSuper createCashAccept(String type,double discount,double basePrice,double returnPrice) {
		CashSuper cs=null;
		if(type.equals("1"))
			cs=new CashNormal();
		else if(type.equals("2"))
			cs=new CashRebate(discount);
		else if(type.equals("3"))
			cs=new CashReturn(basePrice,returnPrice);
		return cs;
	}
}

缺点:每次增加减少收费方式的时候都要对工厂类进行改动,不符合开放封闭原则。

4.改进:(策略模式下的收费系统)
将根据type判断是那个收费类的职责交给客户端,即工厂类中不能出现具体的收费方法类,用它们的父类代替,并为其传入具体的收费方式对象。

package computer;

import java.util.Scanner;

public class Test {
	public static void main(String[] args) {
		Scanner cin=new Scanner(System.in);
		CashSuper cs=null;
		boolean flag=true;
		String list="";
		double totalPrice=0.00;
		
		double price=0,num=0,discount=0;
		while(flag) {
			System.out.print("请输入单价:");
			price=Double.parseDouble(cin.next());
			
			System.out.print("请输入数量:");
			num=Double.parseDouble(cin.next());
			
			System.out.print("请输入折扣类型(1无折扣 2打折 3 满减):");
			String type=cin.next();
			
			if(type.equals("1")) {
				cs=new CashNormal();
			}
			
			else if(type.equals("2")) {
				System.out.print("请输入折扣:");
				discount=Double.parseDouble(cin.next());
				cs=new CashRebate(discount);
			}
			
			else if(type.equals("3")) {
				System.out.print("请输入返现基础金额:");
				String basePrice=cin.next();
				System.out.print("请输入返现金额:");
				String returnPrice=cin.next();
				cs=new CashReturn(Double.parseDouble(basePrice),Double.parseDouble(returnPrice));
			}
			
			double xiaoji=price*num;
			CashAcceptFactory caf=new CashAcceptFactory(cs);
			
			xiaoji=caf.getResult(xiaoji);
			list+="单价"+price+",数量"+num+",折扣"+discount+",小计"+xiaoji+"\n";
			totalPrice+=xiaoji;
			
			if(totalPrice>10)
				flag=false;
		}
		
		System.out.println("=====================================================");
		System.out.print("清单:\n"+list);
		System.out.println("总价:"+totalPrice);
	}

}

//抽象现金收取类
abstract class CashSuper{
	//抽象方法(参数为原价,返回当前价)
	public abstract double acceptCash(double money);
}

//正常收费类
class CashNormal extends CashSuper{
	public double acceptCash(double money) {
		return money;
	}
}

//打折收费类
class CashRebate extends CashSuper{
	private double discount=0.00;
	
	public CashRebate(double discount){
		this.discount=discount;
	}
	
	//继承的方法
	public double acceptCash(double money) {
		return money*discount;
	}

	public double getDiscount() {
		return discount;
	}
	public void setDiscount(double discount) {
		this.discount = discount;
	}
	
}

//返利收费类
class CashReturn extends CashSuper{
	//基础金额
	private double baseCash;
	//返现金额
	private double returnCash;

	//构造设置基础金额和返现金额
	public CashReturn(double baseCash, double returnCash) {
		this.baseCash = baseCash;
		this.returnCash = returnCash;
	}
	
	//继承的方法
	public double acceptCash(double money) {
		double result=money;
		if(money>baseCash) {
			result=money-Math.floor(money/baseCash)*returnCash;
		}
		return result;
	}

	public double getBaseCash() {
		return baseCash;
	}

	public void setBaseCash(double baseCash) {
		this.baseCash = baseCash;
	}

	public double getReturnCash() {
		return returnCash;
	}

	public void setReturnCash(double returnCash) {
		this.returnCash = returnCash;
	}
	
}

//现金收取工厂
class CashAcceptFactory{
	//现金收费父类对象
	private CashSuper cs=null;
	//构造方法传入具体的收费类对象
	public CashAcceptFactory(CashSuper cs) {
		this.cs=cs;
	}
	//通过cs调用收费计算方法,得到收费结果
	public double getResult(double money) {
		return cs.acceptCash(money);
	}
}

此时若要增加收费方法,只需要添加新的具体收费类、修改客户端即可。

5.策略模式:
(与简单工厂类似)
在这里插入图片描述

package computer;

public class Test {
	public static void main(String[] args) {
		Context context;
		
		context=new Context(new ConcreteStrategyA());
		context.contextInterface();
		
		context=new Context(new ConcreteStrategyB());
		context.contextInterface();
		
		context=new Context(new ConcreteStrategyC());
		context.contextInterface();
	}
}

//所有算法的公共接口
abstract class Strategy{
	//抽象方法
	public abstract void algorithmInterface();
}

//具体算法A
class ConcreteStrategyA extends Strategy{
	//继承的方法
	public void algorithmInterface() {
		System.out.println("算法A实现。");
	}
}

//具体算法B
class ConcreteStrategyB extends Strategy{
	//继承的方法
	public void algorithmInterface() {
		System.out.println("算法B实现。");
	}
}

//具体算法C
class ConcreteStrategyC extends Strategy{
	//继承的方法
	public void algorithmInterface() {
		System.out.println("算法C实现。");
	}
}

//工厂
class Context{
	//抽象类对象
	Strategy strategy;

	//构造方法初始化抽象类对象
	public Context(Strategy strategy) {
		this.strategy = strategy;
	}
	
	//调用具体策略对象的方法的方法
	public void contextInterface() {
		strategy.algorithmInterface();
	}
}

简单工厂模式与策略模式的对比:
简单工厂模式中用户在使用的是工厂类返回的类
策略模式中用户使用的是工厂类

优点:拓展性好、符合开放封闭原则。
缺点:分支判断放回客户端,改变需求算法时,还是要修改客户端。所有策略类都对外暴露。

6.策略模式与简单工厂结合:
解决:其他都不变,改变工厂类,将分支判断放到工厂类中。

package computer;

import java.util.Scanner;

public class Test {
	public static void main(String[] args) {
		Scanner cin=new Scanner(System.in);
		CashSuper cs=null;
		boolean flag=true;
		String list="";
		double totalPrice=0.00;
		
		double price=0,num=0,discount=0;
		while(flag) {
			System.out.print("请输入单价:");
			price=Double.parseDouble(cin.next());
			
			System.out.print("请输入数量:");
			num=Double.parseDouble(cin.next());
			
			double xiaoji=price*num;
			CashContext cc=new CashContext();
			
			xiaoji=cc.getResult(xiaoji);
			list+="单价"+price+",数量"+num+",折扣"+discount+",小计"+xiaoji+"\n";
			totalPrice+=xiaoji;
			
			if(totalPrice>10)
				flag=false;
		}
		
		System.out.println("=====================================================");
		System.out.print("清单:\n"+list);
		System.out.println("总价:"+totalPrice);
	}

}

//抽象现金收取类
abstract class CashSuper{
	//抽象方法(参数为原价,返回当前价)
	public abstract double acceptCash(double money);
}

//正常收费类
class CashNormal extends CashSuper{
	public double acceptCash(double money) {
		return money;
	}
}

//打折收费类
class CashRebate extends CashSuper{
	private double discount=0.00;
	
	public CashRebate(double discount){
		this.discount=discount;
	}
	
	//继承的方法
	public double acceptCash(double money) {
		return money*discount;
	}

	public double getDiscount() {
		return discount;
	}
	public void setDiscount(double discount) {
		this.discount = discount;
	}
	
}

//返利收费类
class CashReturn extends CashSuper{
	//基础金额
	private double baseCash;
	//返现金额
	private double returnCash;

	//构造设置基础金额和返现金额
	public CashReturn(double baseCash, double returnCash) {
		this.baseCash = baseCash;
		this.returnCash = returnCash;
	}
	
	//继承的方法
	public double acceptCash(double money) {
		double result=money;
		if(money>baseCash) {
			result=money-Math.floor(money/baseCash)*returnCash;
		}
		return result;
	}

	public double getBaseCash() {
		return baseCash;
	}

	public void setBaseCash(double baseCash) {
		this.baseCash = baseCash;
	}

	public double getReturnCash() {
		return returnCash;
	}

	public void setReturnCash(double returnCash) {
		this.returnCash = returnCash;
	}
	
}

//现金收取工厂
class CashContext{
	//现金收费父类对象
	private CashSuper cs=null;
	
	//构造方法分支判断
	public CashContext() {
		Scanner cin=new Scanner(System.in);
		System.out.print("请输入折扣类型(1无折扣 2打折 3 满减):");
		String type=cin.next();
		
		double discount=0;
		double basePrice=0;
		double returnPrice=0;
		
		if(type.equals("1")) {
			cs=new CashNormal();
		}
		
		else if(type.equals("2")) {
			System.out.print("请输入折扣:");
			discount=Double.parseDouble(cin.next());
			cs=new CashRebate(discount);
		}
		
		else if(type.equals("3")) {
			System.out.print("请输入返现基础金额:");
			basePrice=Double.parseDouble(cin.next());
			System.out.print("请输入返现金额:");
			returnPrice=Double.parseDouble(cin.next());
			cs=new CashReturn(basePrice,returnPrice);
		}
	}
	
	//通过cs调用收费计算方法,得到收费结果
	public double getResult(double money) {
		return cs.acceptCash(money);
	}
}

当增加新地收费方法时,只需要添加新的具体收费类、修改工厂类构造函数即可。

简单工厂类地客户端需要知道两个类:收费父类和工厂类;
与简单工厂模式结合的策略模式的客户端只需要认识一个类:工厂类。不需要认识父类,降低模块之间的耦合度。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值