有了OO的基础后,开始认真学习设计模式。
首先学习的是Strategy,下面就封装商场打折策略来分析下策略模式是怎样一回事。
商场每逢节假日都会对不同的商品采用不同的打折策略,首先卖苹果的说我的苹果要打折,好的,我们建立Market和Apple类。
1 /** 2 * 3 * @author LingJian 4 * 5 */ 6 public class Market { 7 8 /** 9 * 只对Apple 10 * @param apple 11 */ 12 public static void normalSell(Apple apple) { 13 System.out.println("未打折价钱:" + apple.getPrice() * apple.getWeight()); 14 } 15 /** 16 * 只对Apple 17 * @param apple 18 */ 19 public static void discountSell(Apple apple) { 20 double weight = apple.getWeight(); 21 //打折算法 22 if(weight < 10) { 23 normalSell(apple); 24 }else if(weight >= 10 && weight < 50) { 25 System.out.println("打八八折价钱:" + apple.getPrice() * apple.getWeight() * 0.88 ); 26 }else if(weight >= 50) { 27 System.out.println("打五折价钱:" + apple.getPrice() * apple.getWeight() * 0.5 ); 28 } 29 } 30 }
1 /** 2 * 3 * @author LingJian 4 * 5 */ 6 public class Apple { 7 //重量 8 private double weight; 9 //单价 实际开发中 涉及金钱等精确计算都是用BigDecimal 10 private double price; 11 12 public double getWeight() { 13 return weight; 4 } 15 public void setWeight(double weight) { 16 this.weight = weight; 17 } 18 public double getPrice() { 19 return price; 20 } 21 public void setPrice(double price) { 22 this.price = price; 23 } 24 public Apple(double weight, double price) { 25 super(); 26 this.weight = weight; 27 this.price = price; 28 } 29 30 31 32 }
/** * * @author LingJian * */ public class Test { /** * @param args */ public static void main(String[] args) { //只能对苹果打折 还不能对通用的一类事物打折 而且都是要卖什么就写什么打折算法 其实每类事物打折算法又是不一致的 Apple apple = new Apple(10.35, 3.6); Market.normalSell(apple); Market.discountSell(apple); } }
节假日过了两天后,卖香蕉的一看,苹果打折促销后,原先买香蕉的都跑去买苹果了,不行,香蕉也要打折,不然卖不出去就烂了,OK,这个时候,我们再往Market加一个卖香蕉的打折方法和Banana类,问题很好的解决了….后来,卖梨卖橙子卖橘子的都来了,但是由于每个商品打折的算法和策略都不一样,咱们只能先往Market不停的加方法….显然这不是很好的设计,不停的写打折方法就说明我们这个打折方法不够通用,扩展性不强,那这个时候怎么办呢?对,肯定是想办法让咱们的打折方法通用,增强扩展性,那么说到扩展我们肯定得想到OO的核心-多态。
这里,我们创建一个Discountable接口,让需要打折的商品都实现这个接口,并且在重写打折方法,这样对于Market来说,我们就把具体的打折实现方式都交给了具体的对象本身来实现,我们就不用担心算法策略不同而不停的增加方法。
/** * * @author LingJian * */ public class Market { /** * 对可打折的一类事物进行打折 * @param apple */ public static void discountSell(Discountable d) { d.discountSell(); } }
public class Apple implements Discountable { //重量 private double weight; //单价 实际开发中 涉及金钱等精确计算都是用BigDecimal private double price; public double getWeight() { return weight; } public void setWeight(double weight) { this.weight = weight; } public double getPrice() { return price; } public void setPrice(double price) { this.price = price; } public Apple(double weight, double price) { super(); this.weight = weight; this.price = price; } @Override public void discountSell() { //打折算法 if(weight < 10) { System.out.println("Apple未打折价钱:" + weight * price); }else if(weight >= 10 && weight < 50) { System.out.println("Apple打八八折价钱:" + weight * price * 0.88 ); }else if(weight >= 50) { System.out.println("Apple打五折价钱:" + weight * price * 0.5 ); } } }
/** * * @author LingJian * */ public class Banana implements Discountable { //重量 private double weight; //单价 实际开发中 涉及金钱等精确计算都是用BigDecimal private double price; public double getWeight() { return weight; } public void setWeight(double weight) { this.weight = weight; } public double getPrice() { return price; } public void setPrice(double price) { this.price = price; } public Banana(double weight, double price) { super(); this.weight = weight; this.price = price; } @Override public void discountSell() { //打折算法 if(weight < 5) { System.out.println("Banana未打折价钱:" + weight * price); }else if(weight >= 5 && weight < 10) { System.out.println("Banana打八八折价钱:" + weight * price * 0.88 ); }else if(weight >= 10) { System.out.println("Banana打五折价钱:" + weight * price * 0.5 ); } } }
/** * * @author LingJian * */ public interface Discountable { public void discountSell(); }
/** * * @author LingJian * */ public class Test { /** * @param args */ public static void main(String[] args) { //可对打折一类事物进行打折啦 先是Apple Discountable d = new Apple(10.35, 3.6); // Discountable d = new Banana(10.35, 1.6); Market.discountSell(d); } }
OK,这一次咱们采用的都是固定的按购买量打折,但是打折的策略算法是有可能变化的,不一定每次节假日都是按购买量打折,所以咱们的打折策略不能写死了,得能够灵活的变化,怎么办呢?当然,还是多态,我们再创建一个Discountor接口,而具体的打折策略都交给具体的实现类来实现,再在需要打折的商品类中,让其持有Discountor接口的实现子类,这样不管每次打折策略怎么变化,我们只需要让打折商品持有不同的实现对象即可灵活的应对变化,这就是策略(Strategy)模式。
/** * * @author LingJian * */ public class Apple implements Discountable { //重量 private double weight; //单价 实际开发中 涉及金钱等精确计算都是用BigDecimal private double price; //按购买量打折 // private Discountor d = new AppleWeightDiscountor(); //按购买总价打折 private Discountor d = new ApplePriceDiscountor(); public double getWeight() { return weight; } public void setWeight(double weight) { this.weight = weight; } public double getPrice() { return price; } public void setPrice(double price) { this.price = price; } public Apple(double weight, double price) { super(); this.weight = weight; this.price = price; } @Override public void discountSell() { d.discount(this); } }
/** * * @author LingJian * */ public interface Discountor { public void discount(Discountable d); }
/** * * @author LingJian * */ public class AppleWeightDiscountor implements Discountor { /** * 按购买量打折 */ @Override public void discount(Discountable d) { Apple apple = (Apple)d; if(apple.getWeight() < 10) { System.out.println("Apple未打折价钱:" + apple.getWeight() * apple.getPrice()); }else if(apple.getWeight() >= 10 && apple.getWeight() < 50) { System.out.println("Apple打八八折价钱:" + apple.getWeight() * apple.getPrice() * 0.88 ); }else if(apple.getWeight() >= 50) { System.out.println("Apple打五折价钱:" + apple.getWeight() * apple.getPrice() * 0.5 ); } } }
/** * * @author LingJian * */ public class ApplePriceDiscountor implements Discountor { /** * 购买满10元立减1角 * 购买满20元立减1元 * 购买满30元立减5元 */ @Override public void discount(Discountable d) { Apple apple = (Apple)d; if(apple.getWeight() * apple.getPrice() < 10) { System.out.println("Apple未打折价钱:" + apple.getWeight() * apple.getPrice()); }else if(apple.getWeight() * apple.getPrice() >= 10 && apple.getWeight() * apple.getPrice() < 20) { System.out.println("Apple购买满10元立减1角:" + (apple.getWeight() * apple.getPrice() - 0.1) ); }else if(apple.getWeight() * apple.getPrice() >= 20 && apple.getWeight() * apple.getPrice() < 30) { System.out.println("Apple购买满20元立减1元:" + (apple.getWeight() * apple.getPrice() - 1) ); }else if(apple.getWeight() * apple.getPrice() >= 30) { System.out.println("Apple购买满30元立减5元:" + (apple.getWeight() * apple.getPrice() - 5) ); } } }
Test类无需改变。
简单的描绘下封装商场打折策略的设计图。如下所示:
Market负责给Discountable的商品打折,而具体的可打折的商品的打折的算法则交给Discountor的实现子类来具体实现。