設計模式 – 策略模式(Strategy)

實例:商店促銷

(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>

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章