實例:商店促銷
(1)首先考慮用簡單工廠模式進行設計
Ø 客戶端代碼Main.java
package com.yilong.sell.factory;
public class Main {
public static void main(String[] args) {
//SellMethod sellMethod = SellMethodFactory.create("原價");
SellMethod sellMethod = SellMethodFactory.create("方案一");
if(sellMethod != null) {
sellMethod.setPrePrice(10);
sellMethod.setAmount(10);
System.out.println("總價:" + sellMethod.getSumPrice());
} else {
System.out.println("暫未定義該銷售方案!");
}
}
}
Ø 促銷形式類 SellMethod.java
package com.yilong.sell.factory;
public abstract class SellMethod {
private double prePrice;
private int amount;
public abstract double getSumPrice();
public int getAmount() {
return amount;
}
public void setAmount(int amount) {
this.amount = amount;
}
public double getPrePrice() {
return prePrice;
}
public void setPrePrice(double prePrice) {
this.prePrice = prePrice;
}
}
Ø 原價銷售實現類 SellMethodPrototype.java
package com.yilong.sell.factory;
public class SellMethodPrototype extends SellMethod {
@Override
public double getSumPrice() {
return this.getPrePrice() * this.getAmount();
}
}
Ø 打折銷售實現類 SellMethodDiscount.java
package com.yilong.sell.factory;
public class SellMethodDiscount extends SellMethod {
public static final double DISCOUNT = 0.5;
@Override
public double getSumPrice() {
return this.getPrePrice() * this.getAmount() * this.DISCOUNT;
}
}
Ø 銷售方法生產類 SellMethodFactory.java
package com.yilong.sell.factory;
public class SellMethodFactory {
public static SellMethod create(String method) {
SellMethod sellMethod = null;
if(method.equals("原價")) {
sellMethod = new SellMethodPrototype();
} else if(method.equals("方案一")){
sellMethod = new SellMethodDiscount();
}
return sellMethod;
}
}
(2)然後考慮用策略模式實現
Ø 客戶端代碼 Main.java
package com.yilong.sell.strategy;
public class Main {
public static void main(String[] args) {
SellGood sellGood = new SellGood("打5折");
sellGood.setPrePrice(10);
sellGood.setAmount(10);
System.out.println("總價:" + sellGood.getSumPrice());
}
}
Ø 銷售方式類 SellMethod.java
package com.yilong.sell.strategy;
public abstract class SellMethod {
public abstract double getSumPrice(double prePrice, int amount);
}
Ø 原價銷售類 SellMethodPrototype.java
package com.yilong.sell.strategy;
public class SellMethodPrototype extends SellMethod {
@Override
public double getSumPrice(double prePrice, int amount) {
return prePrice * amount;
}
}
Ø 打折銷售類 SellMethodDiscount.java
package com.yilong.sell.strategy;
public class SellMethodDiscount extends SellMethod {
public static final double DISCOUNT = 0.5;
@Override
public double getSumPrice(double prePrice, int amount) {
return prePrice * amount * this.DISCOUNT;
}
}
Ø 銷售類 SellGood.java
package com.yilong.sell.strategy;
public class SellGood {
private double prePrice;
private int amount;
private SellMethod sellMethod = null;
SellGood(String method) {
if(method.equals("原價")) {
sellMethod = new SellMethodPrototype();
} else if(method.equals("打5折")) {
sellMethod = new SellMethodDiscount();
} else {
System.out.println("暫未定義該促銷活動!系統將自動按原價銷售!");
sellMethod = new SellMethodPrototype();
}
}
public double getSumPrice() {
return this.sellMethod.getSumPrice(this.prePrice, this.amount);
}
public int getAmount() {
return amount;
}
public void setAmount(int amount) {
this.amount = amount;
}
public double getPrePrice() {
return prePrice;
}
public void setPrePrice(double prePrice) {
this.prePrice = prePrice;
}
public void setSellMethod(SellMethod sellMethod) {
this.sellMethod = sellMethod;
}
}
由上述設計可知,採用工廠模式和策略模式都可以解決該問題,但是此處採用策略模式比較適合,主要是因爲:
ü 主要是從實際語義上而言,首先銷售方法本身而言就是一種策略(算法)而不是”
產品”
的一種,然後仔細分析,如果設計爲工廠模式,銷售方法將由銷售方法的工廠來創建(create),計算總價的任務就會落在具體的銷售方法類上面,但是銷售方法本身應該屬於銷售商品的一個屬性,而如果設計爲策略模式,那麼銷售方法就會聚合到(has)銷售商品的屬性中,計算總價的任務落在銷售商品類上面,這顯然比較符合實際;
ü 策略模式:它定義了算法家族,分別封裝起來,讓他們之間可以互相替換,此模
式讓算法的變化,不會影響到使用算法的客戶;
ü 再結合本例子分析,商場銷售的方式是經常變動的,採用工廠模式不能很好地解決
算法經常變動的情況,而策略模式是一種定義一系列算法的方法,從概念上來看所有這些方法完成的都是相同的工作,只是實現不同,他可以用相同的方式調用所有的算法,減少了各種算法類與使用算法類之間的耦合;
ü 策略模式的Strategy類層次爲Context定義了以系列的可供重用的算法或行爲,
繼承有助於析取出這些算法中的公共功能,上述例子中對於打折、返利或者其他的算法,其實都是對實際商品收費的一種計算,通過繼承,可以得到他們計算總價的公共功能;
ü 策略模式還簡化了單元測試,因爲每個算法都有自己的類,可以通過自己的接口單
獨測試;
ü 策略模式就是用來封裝算法的,但在實踐中,我們發現可以用它來封裝幾乎任何類
型的規則,只要在分析過程中聽到需要在不同時間應用不同的業務規則,就可以考慮使用策略模式處理這種變化的可能性;
ü 策略模式和工廠模式結合後還可以大大減輕了客戶端的職責;
使用配置文件:
Ø 文件SellGood.java
package com.yilong.sell.strategy;
public class SellGood {
private double prePrice;
private int amount;
private SellMethod sellMethod = null;
SellGood(String method) {
ApplicationContext applicationContext =
new ClassPathXmlApplicationContext("sellmethods.xml");
sellMethod = (SellMethod)
applicationContext.getSellMethod(method);
if(sellMethod == null) {
System.out.println("暫未定義該促銷形式! 系統將按照原價銷售!");
sellMethod = (SellMethod)
applicationContext.getSellMethod("原價");
}
}
public double getSumPrice() {
return this.sellMethod.getSumPrice(this.prePrice, this.amount);
}
public int getAmount() {
return amount;
}
public void setAmount(int amount) {
this.amount = amount;
}
public double getPrePrice() {
return prePrice;
}
public void setPrePrice(double prePrice) {
this.prePrice = prePrice;
}
public void setSellMethod(SellMethod sellMethod) {
this.sellMethod = sellMethod;
}
}
Ø 文件ApplicationContext.java
package com.yilong.sell.strategy;
public interface ApplicationContext {
Object getSellMethod(String methodKey);
}
Ø 文件ClassPathXmlApplicationContext.java
package com.yilong.sell.strategy;
import java.io.IOException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.jdom.Document;
import org.jdom.Element;
import org.jdom.JDOMException;
import org.jdom.input.SAXBuilder;
public class ClassPathXmlApplicationContext implements ApplicationContext {
private Map<String, Object> sellMethods =
new HashMap<String, Object>();
public ClassPathXmlApplicationContext(String xmlname) {
try {
SAXBuilder saxBuilder = new SAXBuilder();
Document doc = saxBuilder.build(this.getClass().
getClassLoader().getResourceAsStream(xmlname));
Element root = doc.getRootElement();
List list = root.getChildren("sellmethod");
for (int i = 0; i < list.size(); i++) {
Element element = (Element) list.get(i);
String id = element.getAttributeValue("id");
String clazz = element.getAttributeValue("class");
Object sellMethodClass;
sellMethodClass = Class.forName(clazz).newInstance();
sellMethods.put(id, sellMethodClass);
}
} catch (JDOMException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
public Object getSellMethod(String methodKey) {
return sellMethods.get(methodKey);
}
}
Ø 文件sellmethods.xml
<sellmethods>
<sellmethod id="原價"
class="com.yilong.sell.strategy.SellMethodPrototype">
</sellmethod>
<sellmethod id="打5折"
class="com.yilong.sell.strategy.SellMethodDiscount">
</sellmethod>
</sellmethods>