黑马程序员-策略模式

---------------------- <a href="http://www.itheima.com"target="blank">ASP.Net+Unity开发</a>、<a href="http://www.itheima.com"target="blank">.Net培训</a>、期待与您交流! ----------------------

引入:商城收银软件,给出商品的价格,数量,要求算出商品的总价

(如果我们接到这道题,我们一般会这样写)

Strategy类,Product类,CalculateTotal

Strategy


public class Strategy {

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		Product product = new Product("桃子", 10, 0.8, 3);
		Product product1 = new Product("苹果", 10, 0.8, 3);
		CalculateTotal cal = new CalculateTotal();
		cal.addProduct(product);
		cal.addProduct(product1);
		double total = cal.caculate();
		System.out.println(total);

	}

}

Product

public class Product {

	private String name;
	private int number;
	private double discount;
	private double unitPrice;

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public int getNumber() {
		return number;
	}

	public void setNumber(int number) {
		this.number = number;
	}

	public double getDiscount() {
		return discount;
	}

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

	public Product(String name, int number, double discount, double unitPrice) {
		super();
		this.name = name;
		this.number = number;
		this.discount = discount;
		this.unitPrice = unitPrice;
	}

	public double getUnitPrice() {
		return unitPrice;
	}

	public void setUnitPrice(double unitPrice) {
		this.unitPrice = unitPrice;
	}

	public Product() {
	}
}

CalculateTotal

import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;

public class CalculateTotal {

	public Map<String, Product> map = new HashMap<String, Product>();

	public void addProduct(Product p) {
		map.put(p.getName(), p);
	}

	public double caculate() {
		Set<String> keyset = map.keySet();
		Iterator<String> it = keyset.iterator();
		double total = 0;
		while (it.hasNext()) {
			String key = it.next();
			Product product = map.get(key);
			double unitPrice = product.getUnitPrice();
			double discount = product.getDiscount();
			int number = product.getNumber();
			total = total + unitPrice * number * discount;
		}
		return total;
	}
}

这种写法貌似很好,也符合了面向对象的设计原则,但是仔细想想,他并不灵活,假如对于同一件商品,列如桃子,现在国庆节,五折出售,国庆节过后,不打折,但是满100返还20,元旦到了,商家决定在打八折的基础上满50返还5元,对于这种情况,“优惠措施是多变的”,我们这种设计并不合适。

修改:策略模式

CashRetrun(满多少返还)类,CashRebate类(打折),CashNormal类(无折扣),CashSuper类(这三个类的父接口),Product(商品类),Client(客户端,维护对CashSuper类的一个引用)

CashReturn

package strategy;

public class CashReturn implements CashSuper {

	private int reCash;
	private int cashCondition;

	@Override
	public double getResult(Product p) {
		// TODO Auto-generated method stub
		int result = p.getUnitPrice() * p.getNumber();
		return result > cashCondition ? result - cashCondition : result;
	}

	public CashReturn(int reCash, int cashCondition) {
		super();
		this.reCash = reCash;
		this.cashCondition = cashCondition;
	}

}

CashRebate

package strategy;

public class CashRebate implements CashSuper {

	private int cashRebate;

	@Override
	public double getResult(Product p) {
		// TODO Auto-generated method stub
		return p.getNumber() * p.getUnitPrice() * cashRebate;
	}

	public CashRebate(int cashRebate) {
		super();
		this.cashRebate = cashRebate;
	}

}

CashNormal

package strategy;

public class CashNormal implements CashSuper {

	@Override
	public double getResult(Product p) {

		return p.getNumber() * p.getUnitPrice();
	}

}

CashSuper

package strategy;

public interface CashSuper {
	double getResult(Product p);

}

Product

package strategy;

public class Product {

	private String name;
	private int number;
	private int unitPrice;

	public int getUnitPrice() {
		return unitPrice;
	}

	public void setUnitPrice(int unitPrice) {
		this.unitPrice = unitPrice;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public int getNumber() {
		return number;
	}

	public Product(String name, int number) {
		super();
		this.name = name;
		this.number = number;
	}

	public void setNumber(int number) {
		this.number = number;
	}

	public Product() {
	}
}

Client

package strategy;

import java.util.Scanner;

public class Client {

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		boolean flag = true;
		int totalCash = 0;
		CashSuper cashSuper = null;
		Scanner scanner = new Scanner(System.in);
		while (flag) {
			System.out.println("输入商品数量:");
			int number = scanner.nextInt();
			System.out.println("请输入商品单价");
			int unitPrice = scanner.nextInt();
			Product product = new Product();
			product.setNumber(number);
			product.setUnitPrice(unitPrice);
			System.out.println("请选择优惠策略1、不打折            2满则返还      3打折");
			int strategy = scanner.nextInt();
			if (strategy == 1) {
				cashSuper = new CashNormal();
			} else if (strategy == 2) {
				System.out.println("请输入满足条件及返还金额");
				int cashCondition = scanner.nextInt();
				int cashReturn = scanner.nextInt();
				cashSuper = new CashReturn(cashCondition, cashReturn);
			} else if (strategy == 3) {
				System.out.println("请输入打折率");
				int cashRebate = scanner.nextInt();
				cashSuper = new CashRebate(cashRebate);
			}
			totalCash = (int) (totalCash + cashSuper.getResult(product));
			System.out.println("是否继续输入y/n");
			String condition = scanner.next();
			flag = condition.equals("y");
		}
		System.out.println(totalCash);

	}

}

这就是策略模式,很好的解决了这类问题,但是客户端做了大多判断,我们针对这种情况可以进一步进行修改,(策略模式+简单工厂),将判断逻辑从Client层分离

CashFactory

package strategy;

import java.util.Scanner;

public class CashFactory {

	static CashSuper cashSuper = null;
	static Scanner scanner = new Scanner(System.in);

	public static CashSuper getResult(int strategy) {
		if (strategy == 1) {
			cashSuper = new CashNormal();
		} else if (strategy == 2) {
			System.out.println("请输入满足条件及返还金额");
			int cashCondition = scanner.nextInt();
			int cashReturn = scanner.nextInt();
			cashSuper = new CashReturn(cashCondition, cashReturn);
		} else if (strategy == 3) {
			System.out.println("请输入打折率");
			double cashRebate = scanner.nextDouble();
			cashSuper = new CashRebate(cashRebate);
		}
		return cashSuper;
	}
}

Client

package strategy;

import java.util.Scanner;

public class Client {

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		boolean flag = true;
		int totalCash = 0;
		CashSuper cashSuper = null;
		Scanner scanner = new Scanner(System.in);
		while (flag) {
			System.out.println("输入商品数量:");
			int number = scanner.nextInt();
			System.out.println("请输入商品单价");
			int unitPrice = scanner.nextInt();
			Product product = new Product();
			product.setNumber(number);
			product.setUnitPrice(unitPrice);
			System.out.println("请选择优惠策略1、不打折            2满则返还      3打折");
			int strategy = scanner.nextInt();
			cashSuper = CashFactory.getResult(strategy);
			totalCash = (int) (totalCash + cashSuper.getResult(product));
			System.out.println("是否继续输入y/n");
			String condition = scanner.next();
			flag = condition.equals("y");
		}
		System.out.println(totalCash);

	}

}

总结:策略模式的优点与适用场合

优点:

1、策略模式是一种定义一系列算法的方法,所有的这些算法都完成相同的工作,只是实现不同,利用策略模式可以以相同的方式调用所有的算法,减少各种算法类与使用算法类之间的耦合性.

2、有利于简化各个算法的单元测试,每个算法的变动对其他算法没有影响

3、将行为封装在一个个单独的算法类中,可以避免在一个单独的类中使用多个条件判断

适用场合

          策略模式是用来封装算法的。实践中可以用它来封装几乎任何类型的规则,只要在分析过程中,需要用到不同时间应用不同规则,就可以使用策略模式封装变化的可能性

策略模式的组成:
1、抽象策略角色:策略类,通常由一个接口或者抽象类实现

2、具体策略角色:包括了相关的算法和行为,可能不止一个具体策略角色

3、环境角色:持有一个策略类的引用,最终给客户端调用的

接下来老师用配置+反射完成,不过我觉得太过繁琐,而且针对这种优惠措施多变的情况,用配置+反射也并没有消除逻辑判断,所以后面的没写,现在附上核心代码。

 在用反射时如何反射带参数的构造函数

<?xml version="1.0" encoding="utf-8" standalone="no"?>
<!DOCTYPE properties SYSTEM "http://java.sun.com/dtd/properties.dtd">
<properties>
<entry key="+">demo4.AddFactory</entry>
<entry key="-">demo4.SubtractionFactory</entry>
</properties>

注意配置文件的格式,本来不打算写了,但仔细一想,虽然理解了,但实际操作可能又会发生好多问题,就又敲了一遍,果然如此。

CashFactory

package strategy1;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.lang.reflect.Constructor;
import java.util.InvalidPropertiesFormatException;
import java.util.Properties;
import java.util.Scanner;

public class CashFactory {

	static CashSuper cashSuper = null;
	static Scanner scanner = new Scanner(System.in);

	public static CashSuper getResult(int strategy) throws Exception {
		Object[] args;
		if (strategy == 1) {
			cashSuper = new CashNormal();
		} else if (strategy == 2) {

			System.out.println("请输入满足条件及返还金额");
			int cashCondition = scanner.nextInt();
			int cashReturn = scanner.nextInt();
			args = new Object[] { cashCondition, cashReturn };
			cashSuper = (CashSuper) reflect(2, args);

		} else if (strategy == 3) {
			System.out.println("请输入打折率");
			double cashRebate = scanner.nextDouble();
			args = new Object[] { cashRebate };
			cashSuper = (CashSuper) reflect(3, args);
		}
		return cashSuper;

	}

	public static Object reflect(int type, Object[] args) throws Exception {
		Properties prop = new Properties();

		prop.loadFromXML(new FileInputStream(new File("config.xml")));
		String className = prop.getProperty(type + "");
		System.out.println(args.length);
		Class c = Class.forName(className);
		Class[] argsClass = new Class[args.length];
		for (int i = 0; i < args.length; i++) {
			argsClass[i] = args[i].getClass();

		}
		Constructor cons = c.getConstructor(argsClass);
		return cons.newInstance(args);

	}

}

Client

package strategy1;

import java.util.Scanner;

public class Client {

	/**
	 * @param args
	 * @throws Exception
	 */
	public static void main(String[] args) throws Exception {
		// TODO Auto-generated method stub
		boolean flag = true;
		int totalCash = 0;
		CashSuper cashSuper = null;
		Scanner scanner = new Scanner(System.in);
		while (flag) {
			System.out.println("输入商品数量:");
			int number = scanner.nextInt();
			System.out.println("请输入商品单价");
			int unitPrice = scanner.nextInt();
			Product product = new Product();
			product.setNumber(number);
			product.setUnitPrice(unitPrice);
			System.out.println("请选择优惠策略1、不打折            2满则返还      3打折");
			int strategy = scanner.nextInt();
			cashSuper = CashFactory.getResult(strategy);
			totalCash = (int) (totalCash + cashSuper.getResult(product));
			System.out.println("是否继续输入y/n");
			String condition = scanner.next();
			flag = condition.equals("y");
		}
		System.out.println(totalCash);

	}

}

本来打算这样就好了,可是一运行,竟然报错

可是仔细检查CashReturn有这样的构造函数啊

public CashReturn(int reCash, int cashCondition) {
super();
this.reCash = reCash;
this.cashCondition = cashCondition;
}

后找老师帮忙,得以解决

修改如下:

public CashReturn(Integer reCash, Integer cashCondition) {
super();
this.reCash = reCash;
this.cashCondition = cashCondition;
}
 


--------------------- <a href="http://www.itheima.com"target="blank">ASP.Net+Unity开发</a>、<a href="http://www.itheima.com"target="blank">.Net培训</a>、期待与您交流! ----------------------

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值