行爲型之設計模式

簡述

設計模式類型有3種(行爲型,創建型,結構型),以下逐一列出行爲型類型的設計模式:
模板方法,命令模式,訪問者模式,迭代器模式,觀察者模式,中介者,備忘錄,解釋器,狀態,策略,職責連模式(責任鏈模式)

一、策略模式

封裝多中計算方式的算法包。

一個簡單的使用場景

需求場景:
電影院爲不同類型用戶提供不同電影票的打折方式,方案:
1 學生憑學生證享受8折優惠
2 年齡在1-週歲及以下兒童可享受每張電影票減免10元優惠(原始票價不能低於20)
3 vip 用戶可享受5折優惠,與此同時額外獲取積分,可用積分兌換影院贈品
後期可能還會有優惠折扣方案。

分析場景,抽離出關鍵點的簡圖

1 涉及到折扣方案的封裝
2 針對不同角色的切換
3 後期要考慮的複用。
確認過眼神,正對策略模式。

4此場景的開發簡圖:
上圖

實操demo

 public class Client {
    public static void main(String[] args) {
        //業務中通過一些前置條件,判斷走孩子/vip/學生  折扣類
        BigDecimal originPrice=new BigDecimal("79.99");
        new MovieTicket(originPrice,new ChildrenDiscount()).getPrice();;

        originPrice=new BigDecimal("88");
         new MovieTicket(originPrice,new VIPDiscount()).getPrice();
 }
}
/**環境策略角色*/
public class MovieTicket {
    BigDecimal price;
    Discount discount;
    public MovieTicket(BigDecimal price,Discount discount) {
        this.price=price;
        this.discount=discount;
        System.out.println("原始票價爲:"+price.toString());
    }
    public BigDecimal getPrice() {
        return discount.calculate(this.price);
    }

    public void setPrice(BigDecimal originPrice) {
        this.price = originPrice;
    }

    public void setDiscount(Discount discount) {
       this.discount=discount;
    }
}
/**抽象策略角色*/
public interface Discount {
   BigDecimal calculate(BigDecimal originPrice);
}
/**具體策略角色*/
public class StudentDiscount implements Discount {
    private final BigDecimal DISCOUNT=new BigDecimal("0.8");
    @Override
    public BigDecimal calculate(BigDecimal originPrice) {
        BigDecimal price= originPrice.multiply(DISCOUNT).setScale(2,BigDecimal.ROUND_HALF_UP);
        System.out.println("學生票價:"+price.toString());
        return price;
    }
}
/**具體策略角色*/
public class ChildrenDiscount implements Discount{
    private final BigDecimal DISCOUNT=new BigDecimal(10);

    @Override
    public BigDecimal calculate(BigDecimal originPrice) {
        BigDecimal price=originPrice.compareTo(new BigDecimal(20))>=0?originPrice.subtract(DISCOUNT):originPrice;
        System.out.println("原票價至少20元,少兒票價方可優惠:"+price.toString());
        return price;
    }
}
/**具體策略角色*/
public class VIPDiscount implements  Discount {
    private final BigDecimal DISCOUNT=new BigDecimal("0.5");
    @Override
    public BigDecimal calculate(BigDecimal originPrice) {
        BigDecimal price= originPrice.multiply(DISCOUNT);
        System.out.println("VIP票價:"+price.toString()+"可積分");
        return price;
    }
}

以上爲策略模式小demo,看到這就可以直接看小結了。
代碼上傳到csdn了,可以下載測試。

策略模式小結

工作中使用率蠻高的。
同類場景,eg1: 借貸平臺的還款方式,可用策略模式去計算不同的還款方式:一次性還本付息,先息後本,等額本金,等額本息,彈性還款,這些算法包均可作爲具體策略角色進行封裝。
eg2:接存管平臺接口開發時,比如預處理,調用接口 以及後處理,可以採取策略模式。

優點小結:
1 對某一業務數據操作行爲有多個算法包,客戶針對自己需求調用其中的一個算法。
2 可靈活切換,可複用,封裝多個算法包,完美滿足設計模式開閉原則,可擴展性強。

據說的劣勢,客戶端要知道每種算法的用戶,然後對自己的需求去調用,但如果算法方案是從客戶端需求發起呢,哈哈,工作中一般都是業務方發起需求,驅動科技落地,如果是這種,那麼該缺點可以忽略。

以上小結僅供參考,並不全面,僅個人看中的層面的總結,如有差錯,請不吝指教~

附註:

如果你還想要使用xml形式,可參看下面追加code。將具體策略模式配置到xml文件中,每次新加策略後,在xml文件中改一下重啓一下服務即可,實現方式如下:

/** 1 Client2.class 將具體策略角色類配置到xml中,通過xml解析工具類獲取該具體策略角色類的實例走後續流程*/
public class Client2 {
    public static void main(String[] args) {
        BigDecimal originalPrice=new BigDecimal(60.0);
        Discount disount=(Discount) XMLUtil.getBean();;//讀取配置文件並反射生成具體折扣對象
        MovieTicket mt=new MovieTicket(originalPrice,disount);
        mt.getPrice();

    }
}
2 添加xml文件解析工具包

import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import java.io.File;
import java.io.IOException;

public class XMLUtil {
    //該方法用於從xml配置文件中提取具體類的類名,並返回一個實例對象
    public static Object getBean(){
        try {
        DocumentBuilderFactory dFactory=DocumentBuilderFactory.newInstance();
        DocumentBuilder builder=dFactory.newDocumentBuilder();
        Document doc;
            doc=builder.parse(new File("src//strategyBook//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;
        }
    }
}
3config.xml配置文件
<?xml version="1.0" encoding="UTF-8"?>
<config>
        <className>strategyBook.VIPDiscount</className>
</config>

xml配置具體策略角色:
優點:每次新增可添加具體策略角色類,同步修改xml文件後重啓即可。清晰明瞭
缺點,不夠靈活,試想,面對的前置條件是不同角色,要走各自對應的具體策略角色,那豈不是每走完一次數據 都要修改配置文件,然後重啓服務?

參閱:
[1]: java設計模式,劉偉 編著

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