七:策略模式(不同等级会员打折算法)
定義:策略模式定義了一系列的算法,并將每一個算法封裝起來,而且使它們還可以相互替換。策略模式讓算法獨立于使用它的客戶而獨立變化;
下面給出策略模式的類圖,引自百度百科。
策略模式在LZ第一次接觸到的時候,LZ是這么理解的,就是如果我們想往一個方法當中插入隨便一段代碼的話,就是策略模式。即如下形式。
public class MyClass {
public void myMethod(){
System.out.println("方法里的代碼");
//LZ想在這插入一段代碼,而且這個代碼是可以改變的,想怎么變就怎么變
System.out.println("方法里的代碼");
}
}
在JAVA中,接口可以滿足LZ的這一過分要求,我們可以設計一個接口,并當做參數傳進去,就能達到這個效果了。我們來看,先定義一個接口。
public interface MyInterface {
//我想插入的代碼
void insertCode();
}
將原來的類改成這樣,傳遞一個接口進去。
public class MyClass {
public void myMethod(MyInterface myInterface){
System.out.println("方法里的代碼");
//你看我是不是插進來一段代碼?而且這段代碼是可以隨便改變的
myInterface.insertCode();
System.out.println("方法里的代碼");
}
}
我們只要實現了MyInterface這個接口,在insertCode方法中寫入我們想要插進去的代碼,再將這個類傳遞給myMethod方法,就可以將我們隨手寫的代碼插到這個方法當中。比如這樣。
class InsertCode1 implements MyInterface{
public void insertCode() {
System.out.println("我想插進去的代碼,第一種");
}
}
class InsertCode2 implements MyInterface{
public void insertCode() {
System.out.println("我想插進去的代碼,第二種");
}
}
這樣我們在調用myMethod方法時就可以隨意往里面插入代碼了,比如。
//客戶端調用
public class Client {
public static void main(String[] args) {
MyClass myClass = new MyClass();
myClass.myMethod(new InsertCode1());
System.out.println("--------------------");
myClass.myMethod(new InsertCode2());
}
}
那么運行出來的結果就是我們成功的將兩端代碼插入到了myMethod方法中,以上所講的算是JAVA中一種技術層面的實現,就是傳入一個接口,封裝代碼。那么既然談到設計模式,就要有設計模式的應用場景,有關策略模式,所產生的形式就和上述是一模一樣的,只是我們適當的給予模式的應用場景,就會讓它變的更有價值。
上面的例子代碼清晰但卻理解起來很生硬,下面LZ舉一個具有實際意義的例子。
就比如我們要做一個商店的收銀系統,這個商店有普通顧客,會員,超級會員以及金牌會員的區別,針對各個顧客,有不同的打折方式,并且一個顧客每在商店消費1000就增加一個級別,那么我們就可以使用策略模式,因為策略模式描述的就是算法的不同,而且這個算法往往非常繁多,并且可能需要經常性的互相替換。
這里我們舉例就采用最簡單的,以上四種顧客分別采用原價,八折,七折和半價的收錢方式。
那么我們首先要有一個計算價格的策略接口,如下。
public interface CalPrice {
//根據原價返回一個最終的價格
Double calPrice(Double originalPrice);
}
下面我們給出四個計算方式。
class Common implements CalPrice{
public Double calPrice(Double originalPrice) {
return originalPrice;
}
}
class Vip implements CalPrice{
public Double calPrice(Double originalPrice) {
return originalPrice * 0.8;
}
}
class SuperVip implements CalPrice{
public Double calPrice(Double originalPrice) {
return originalPrice * 0.7;
}
}
class GoldVip implements CalPrice{
public Double calPrice(Double originalPrice) {
return originalPrice * 0.5;
}
}
以上四種計算方式非常清晰,分別是原價,八折,七折和半價。下面我們看客戶類,我們需要客戶類幫我們完成客戶升級的功能。
//客戶類
public class Customer {
private Double totalAmount = 0D;//客戶在本商店消費的總額
private Double amount = 0D;//客戶單次消費金額
private CalPrice calPrice = new Common();//每個客戶都有一個計算價格的策略,初始都是普通計算,即原價
//客戶購買商品,就會增加它的總額
public void buy(Double amount){
this.amount = amount;
totalAmount += amount;
if (totalAmount > 3000) {//3000則改為金牌會員計算方式
calPrice = new GoldVip();
}else if (totalAmount > 2000) {//類似
calPrice = new SuperVip();
}else if (totalAmount > 1000) {//類似
calPrice = new Vip();
}
}
//計算客戶最終要付的錢
public Double calLastAmount(){
return calPrice.calPrice(amount);
}
}
下面我們看客戶端調用,系統會幫我們自動調整收費策略。
//客戶端調用
public class Client {
public static void main(String[] args) {
Customer customer = new Customer();
customer.buy(500D);
System.out.println("客戶需要付錢:" + customer.calLastAmount());
customer.buy(1200D);
System.out.println("客戶需要付錢:" + customer.calLastAmount());
customer.buy(1200D);
System.out.println("客戶需要付錢:" + customer.calLastAmount());
customer.buy(1200D);
System.out.println("客戶需要付錢:" + customer.calLastAmount());
}
}
運行以后會發現,第一次是原價,第二次是八折,第三次是七折,最后一次則是半價。我們這樣設計的好處是,客戶不再依賴于具體的收費策略,依賴于抽象永遠是正確的。不過上述的客戶類實在有點難看,尤其是buy方法,我們可以使用簡單工廠來稍微改進一下它。我們建立如下策略工廠。
//我們使用一個標準的簡單工廠來改進一下策略模式
public class CalPriceFactory {
private CalPriceFactory(){}
//根據客戶的總金額產生相應的策略
public static CalPrice createCalPrice(Customer customer){
if (customer.getTotalAmount() > 3000) {//3000則改為金牌會員計算方式
return new GoldVip();
}else if (customer.getTotalAmount() > 2000) {//類似
return new SuperVip();
}else if (customer.getTotalAmount() > 1000) {//類似
return new Vip();
}else {
return new Common();
}
}
}
這樣我們就將制定策略的功能從客戶類分離了出來,我們的客戶類可以變成這樣。
//客戶類
public class Customer {
private Double totalAmount = 0D;//客戶在本商店消費的總額
private Double amount = 0D;//客戶單次消費金額
private CalPrice calPrice = new Common();//每個客戶都有一個計算價格的策略,初始都是普通計算,即原價
//客戶購買商品,就會增加它的總額
public void buy(Double amount){
this.amount = amount;
totalAmount += amount;
/* 變化點,我們將策略的制定轉移給了策略工廠,將這部分責任分離出去 */
calPrice = CalPriceFactory.createCalPrice(this);
}
//計算客戶最終要付的錢
public Double calLastAmount(){
return calPrice.calPrice(amount);
}
public Double getTotalAmount() {
return totalAmount;
}
public Double getAmount() {
return amount;
}
}
現在比之前來講,我們的策略模式更加靈活一點,但是相信看過LZ博文的都知道,LZ最不喜歡elseif,所以策略模式也是有缺點的,就是當策略改變時,我們需要使用elseif去判斷到底使用哪一個策略,哪怕使用簡單工廠,也避免不了這一點。比如我們又添加一類會員,那么你需要去添加elseif。再比如我們的會員現在打九折了,那么你需要添加一個九折的策略,這沒問題,我們對擴展開放,但是你需要修改elseif的分支,將會員的策略從八折替換為九折,這是簡單工廠的詬病,在之前已經提到過,對修改開放。
總結
以上是生活随笔為你收集整理的七:策略模式(不同等级会员打折算法)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 浅谈随机数的生成
- 下一篇: 图解Apache Mina