演算法的封裝與切換——策略模式(三)
24.3 完整解決方案
為了實現打折演算法的複用,並能夠靈活地向系統中增加新的打折方式,Sunny軟體公司開發人員使用策略模式對電影院打折方案進行重構,重構後基本結構如圖24-2所示:
在圖24-2中,MovieTicket充當環境類角色,Discount充當抽象策略角色,StudentDiscount、 ChildrenDiscount 和VIPDiscount充當具體策略角色。完整程式碼如下所示:
//電影票類:環境類
class MovieTicket {
private double price;
private Discount discount; //維持一個對抽象折扣類的引用
public void setPrice(double price) {
this.price = price;
}
//注入一個折扣類物件
public void setDiscount(Discount discount) {
this.discount = discount;
}
public double getPrice() {
//呼叫折扣類的折扣價計算方法
return discount.calculate(this.price);
}
}
//折扣類:抽象策略類
interface Discount {
public double calculate(double price);
}
//學生票折扣類:具體策略類
class StudentDiscount implements Discount {
public double calculate(double price) {
System.out.println("學生票:");
return price * 0.8;
}
}
//兒童票折扣類:具體策略類
class ChildrenDiscount implements Discount {
public double calculate(double price) {
System.out.println("兒童票:");
return price - 10;
}
}
//VIP會員票折扣類:具體策略類
class VIPDiscount implements Discount {
public double calculate(double price) {
System.out.println("VIP票:");
System.out.println("增加積分!");
return price * 0.5;
}
}
為了提高系統的靈活性和可擴充套件性,我們將具體策略類的類名儲存在配置檔案中,並通過工具類XMLUtil來讀取配置檔案並反射生成物件,XMLUtil類的程式碼如下所示:
import javax.xml.parsers.*;
import org.w3c.dom.*;
import org.xml.sax.SAXException;
import java.io.*;
class XMLUtil {
//該方法用於從XML配置檔案中提取具體類類名,並返回一個例項物件
public static Object getBean() {
try {
//建立文件物件
DocumentBuilderFactory dFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = dFactory.newDocumentBuilder();
Document doc;
doc = builder.parse(new File("config.xml"));
//獲取包含類名的文字節點
NodeList nl = doc.getElementsByTagName("className");
Node classNode=nl.item(0).getFirstChild();
String cName=classNode.getNodeValue();
//通過類名生成例項物件並將其返回
Class c=Class.forName(cName);
Object obj=c.newInstance();
return obj;
}
catch(Exception e) {
e.printStackTrace();
return null;
}
}
}
在配置檔案config.xml中儲存了具體策略類的類名,程式碼如下所示:
<?xml version="1.0"?>
<config>
<className>StudentDiscount</className>
</config>
編寫如下客戶端測試程式碼:
class Client {
public static void main(String args[]) {
MovieTicket mt = new MovieTicket();
double originalPrice = 60.0;
double currentPrice;
mt.setPrice(originalPrice);
System.out.println("原始價為:" + originalPrice);
System.out.println("---------------------------------");
Discount discount;
discount = (Discount)XMLUtil.getBean(); //讀取配置檔案並反射生成具體折扣物件
mt.setDiscount(discount); //注入折扣物件
currentPrice = mt.getPrice();
System.out.println("折後價為:" + currentPrice);
}
}
編譯並執行程式,輸出結果如下:
原始價為:60.0 --------------------------------- 學生票: 折後價為:48.0 |
如果需要更換具體策略類,無須修改原始碼,只需修改配置檔案,例如將學生票改為兒童票,只需將儲存在配置檔案中的具體策略類StudentDiscount改為ChildrenDiscount,如下程式碼所示:
<?xml version="1.0"?>
<config>
<className>ChildrenDiscount</className>
</config>
重新執行客戶端程式,輸出結果如下:
原始價為:60.0 --------------------------------- 兒童票: 折後價為:50.0 |
如果需要增加新的打折方式,原有程式碼均無須修改,只要增加一個新的折扣類作為抽象折扣類的子類,實現在抽象折扣類中宣告的打折方法,然後修改配置檔案,將原有具體折扣類類名改為新增折扣類類名即可,完全符合“開閉原則”。
【作者:劉偉 http://blog.csdn.net/lovelion】
相關文章
- 演算法的封裝與切換——策略模式(二)演算法封裝模式
- 【DG】三大模式切換模式
- 封裝頭部切換檢視封裝
- DG_三大模式切換模式
- Weblogic產品模式切換與JVM切換Web模式JVM
- 歸檔模式與非歸檔模式的切換模式
- 三種工廠模式與策略模式模式
- 模板方法模式--封裝演算法模式封裝演算法
- ToolBar封裝策略封裝
- redis sentinel哨兵模式安裝部署和切換Redis模式
- 策略模式、策略模式與Spring的碰撞模式Spring
- 360隨身wifi無線網路卡模式與wifi模式換切換方法WiFi模式
- iOS 封裝頁數控制,點選NavigationTabBar切換頁面iOS封裝NavigationtabBar
- win10怎麼切換到桌面模式_win10平板模式和桌面模式的切換教程Win10模式
- Oracle日誌模式切換Oracle模式
- 商品顯示模式切換模式
- DataGuard切換保護模式模式
- 設計模式(三)Animation中的策略模式設計模式
- 作業三--測試與封裝 5.1封裝
- 如何實現一個地相簿封裝,可以快速切換地圖封裝地圖
- 模板方法模式-封裝一套演算法流程模式封裝演算法
- Java(三)封裝Java封裝
- IMSDK封裝<三>封裝
- Win10怎樣切換平板模式_win10如何切換到平板模式Win10模式
- MVP模式的經典封裝MVP模式封裝
- 鎖定客戶的六大策略:教你如何將切換成本嵌入商業模式模式
- 單體模式封裝模式封裝
- win10安全模式切換正常模式的方法Win10模式
- if else與策略模式模式
- 策略模式與模板方法模式模式
- EDBPPAS(Oracle相容版)Oracle與PostgreSQL相容模式的引數配置切換OracleSQL模式
- Oracle學習系列—歸檔模式的切換Oracle模式
- EDB PPAS(Oracle 相容版) Oracle與PostgreSQL 相容模式的引數配置切換OracleSQL模式
- KindEditor如何切換成簡單模式??模式
- 從簡單恢復模式切換模式
- 委派模式與策略模式記錄模式
- git建立與切換分支Git
- Dozer封裝物件或List的轉換封裝物件