設計模式詳解(四)--------建造者模式

一、定義

將一個複雜對象的構造與它的表示分離,使同樣的構建過程可以創建不同的表示,這樣的設計模式被稱爲建造者模式。

二、使用範圍

1.創建一個複雜的對象,他有多個不同的模塊組成,其中有些模塊不會改變,但是其他模塊可能經常發生改變,我們不得已需要把不變的模塊與常變的模塊分開實現時。

2.當構造過程必須允許被構造的對象有不同表示時。

三、功能實現角色

1.builder:爲創建一個產品對象的各個部件指定抽象接口。

2.ConcreteBuilder:實現Builder的接口以構造和裝配該產品的各個部件,定義並明確它所創建的表示,並 提供一個檢索產品的接口。

3.Director:構造一個使用Builder接口的對象。

4.Product:表示被構造的複雜對象。ConcreteBuilder創建該產品的內部表示並定義它的裝配過程,包含定義組成部件的類,包括將這些部件裝配成最終產品的接口。

四、實踐

1.情景假設

我們在計費的過程中有一個計費模式獲取類,他的功能是獲取當前這個用戶所需要的計費模式,但是計費有很多種,比如SMS計費(短信計費)、Cash計費(銀行卡計費),其中SMS計費又包括中國移動、中國聯通、印尼Tsel、印尼isat計費,Cash包括招商銀行、農行、印尼Visa等,且不同支付方式給予不同的計費點和訂單開頭。在國外用戶和國內用戶時,要提供不同的計費集。

2.當前計費信息接口

public interface FeeInterf {
    public String orderNo();//當前交易編號
    public FeeTypeInterf feeType();//當前交易類型
    public float price();//當前交易金額
}

3.當前計費類型接口

public interface FeeTypeInterf {
    public String feeType();
}

4.當前計費類型的實現類

SMSFeeType

import cn.yzstu.buldermodule.interf.FeeTypeInterf;

/**
 * 類描述
 *
 * @author: 12405
 * @date: 2020/3/25-22:28
 */
public class SMSFeeType implements FeeTypeInterf {

    @Override
    public String feeType() {
        return "SMS";
    }
}

CashFeeType

import cn.yzstu.buldermodule.interf.FeeTypeInterf;

/**
 * 類描述
 *
 * @author: 12405
 * @date: 2020/3/25-22:29
 */
public class CashFeeType implements FeeTypeInterf {
    @Override
    public String feeType() {
        return "Cash";
    }
}

5.不同類型計費的實現類

SMS

import cn.yzstu.buldermodule.impl.feetype.SMSFeeType;
import cn.yzstu.buldermodule.interf.FeeInterf;
import cn.yzstu.buldermodule.interf.FeeTypeInterf;

/**
 * 類描述
 *
 * @author: 12405
 * @date: 2020/3/25-22:37
 */
public abstract class SMSFee implements FeeInterf {

    @Override
    public FeeTypeInterf feeType() {
        return new SMSFeeType();
    }
}

Cash

import cn.yzstu.buldermodule.impl.feetype.CashFeeType;
import cn.yzstu.buldermodule.interf.FeeInterf;
import cn.yzstu.buldermodule.interf.FeeTypeInterf;

/**
 * 類描述
 *
 * @author: 12405
 * @date: 2020/3/25-22:44
 */
public abstract class CashFee implements FeeInterf {
    @Override
    public FeeTypeInterf feeType() {
        return new CashFeeType();
    }
}

6.計費的詳細實體類

中國移動

import java.util.UUID;

/**
 * 類描述
 *
 * @author: 12405
 * @date: 2020/3/25-22:49
 */
public class ChinaMobileFee extends SMSFee {

    @Override
    public String orderNo() {
        return "MOBL"+ UUID.randomUUID();
    }

    @Override
    public float price() {
        return 10.0f;
    }
}

中國聯通

import java.util.UUID;

/**
 * 類描述
 *
 * @author: 12405
 * @date: 2020/3/25-22:52
 */
public class ChinaUnicomFee extends SMSFee{
    @Override
    public String orderNo() {
        return "UNC"+ UUID.randomUUID();
    }

    @Override
    public float price() {
        return 20.0f;
    }
}

印尼TSEl

import java.util.UUID;

/**
 * 類描述
 *
 * @author: 12405
 * @date: 2020/3/25-22:56
 */
public class IndoTselFee extends SMSFee {
    @Override
    public String orderNo() {
        return "TSEL"+ UUID.randomUUID();
    }

    @Override
    public float price() {
        return 2000.0f;
    }
}

印尼ISAT

import java.util.UUID;

/**
 * 類描述
 *
 * @author: 12405
 * @date: 2020/3/25-22:57
 */
public class IndoIsatFee extends SMSFee {
    @Override
    public String orderNo() {
        return "ISAT"+ UUID.randomUUID();
    }

    @Override
    public float price() {
        return 1000.0f;
    }
}

招商銀行

import java.util.UUID;

/**
 * 類描述
 *
 * @author: 12405
 * @date: 2020/3/25-22:58
 */
public class CMBFee extends CashFee {
    @Override
    public String orderNo() {
        return "CMB"+ UUID.randomUUID();
    }

    @Override
    public float price() {
        return 5.0f;
    }
}

農業銀行

/**
 * 類描述
 *
 * @author: 12405
 * @date: 2020/3/25-23:01
 */
public class ABCFee extends CashFee {
    @Override
    public String orderNo() {
        return "ABC"+ UUID.randomUUID();
    }

    @Override
    public float price() {
        return 2.0f;
    }
}

Visa

import java.util.UUID;

/**
 * 類描述
 *
 * @author: 12405
 * @date: 2020/3/25-23:02
 */
public class VisaFee extends CashFee {
    @Override
    public String orderNo() {
        return "V"+ UUID.randomUUID();
    }

    @Override
    public float price() {
        return 10.0f;
    }
}

7.FeeConfig類(用於構建計費相關信息)

import cn.yzstu.bulidermodule.interf.FeeInterf;

import java.util.ArrayList;
import java.util.List;

/**
 * 類描述
 *
 * @author: 12405
 * @date: 2020/3/25-23:09
 */
public class FeeConfig {
    private List<FeeInterf> feeList = new ArrayList<>();

    //往當前訂單中加入可選的支付方式
    public void addFee(FeeInterf feeInterf){
        feeList.add(feeInterf);
    }

    //展示所有可選支付方式的相關信息
    public void showMyFee(){
        for (FeeInterf fee : feeList){
            System.out.println("OrderNo:"+fee.orderNo());
            System.out.println("FeeType:"+fee.feeType().feeType());
            System.out.println("Money:"+fee.price());
        }
    }
}

8.FeeBuilder類(提供給國內外的不同客戶計費集)

import cn.yzstu.bulidermodule.impl.fee.*;

/**
 * 類描述
 *
 * @author: 12405
 * @date: 2020/3/25-23:23
 */
public class FeeBuilder {

    //國內用戶的支付方式
    public FeeConfig prepareChinaFee(){
        FeeConfig feeConfig = new FeeConfig();
        feeConfig.addFee(new ChinaMobileFee());
        feeConfig.addFee(new ChinaUnicomFee());
        feeConfig.addFee(new ABCFee());
        feeConfig.addFee(new CMBFee());
        return feeConfig;
    }

    //國外用戶的支付方式
    public FeeConfig prepareIndoFee(){
        FeeConfig feeConfig = new FeeConfig();
        feeConfig.addFee(new IndoIsatFee());
        feeConfig.addFee(new IndoTselFee());
        feeConfig.addFee(new VisaFee());
        return feeConfig;
    }
}

9.FeeDemo測試(展示國內用戶獲取的計費集)

/**
 * 類描述
 *
 * @author: 12405
 * @date: 2020/3/25-23:30
 */
public class FeeDemo {
    public static void main(String[] args) {
        //獲取國內計費集
        FeeConfig cFeeConfig = FeeBuilder.prepareChinaFee();
        //獲取國外計費集
        FeeConfig iFeeConfig = FeeBuilder.prepareIndoFee();

        //展示國內用戶能夠獲取到的計費集
        cFeeConfig.showMyFee();
    }
}
"C:\Program Files\Java\jdk1.8.0_171\bin\java.exe" "-javaagent:E:\tools\IntelliJ IDEA 2019.3.3\lib\idea_rt.jar=54341:E:\tools\IntelliJ IDEA 2019.3.3\bin" -Dfile.encoding=UTF-8 -classpath "C:\Program Files\Java\jdk1.8.0_171\jre\lib\charsets.jar;C:\Program Files\Java\jdk1.8.0_171\jre\lib\deploy.jar;C:\Program Files\Java\jdk1.8.0_171\jre\lib\ext\access-bridge-64.jar;C:\Program Files\Java\jdk1.8.0_171\jre\lib\ext\cldrdata.jar;C:\Program Files\Java\jdk1.8.0_171\jre\lib\ext\dnsns.jar;C:\Program Files\Java\jdk1.8.0_171\jre\lib\ext\jaccess.jar;C:\Program Files\Java\jdk1.8.0_171\jre\lib\ext\jfxrt.jar;C:\Program Files\Java\jdk1.8.0_171\jre\lib\ext\localedata.jar;C:\Program Files\Java\jdk1.8.0_171\jre\lib\ext\nashorn.jar;C:\Program Files\Java\jdk1.8.0_171\jre\lib\ext\sunec.jar;C:\Program Files\Java\jdk1.8.0_171\jre\lib\ext\sunjce_provider.jar;C:\Program Files\Java\jdk1.8.0_171\jre\lib\ext\sunmscapi.jar;C:\Program Files\Java\jdk1.8.0_171\jre\lib\ext\sunpkcs11.jar;C:\Program Files\Java\jdk1.8.0_171\jre\lib\ext\zipfs.jar;C:\Program Files\Java\jdk1.8.0_171\jre\lib\javaws.jar;C:\Program Files\Java\jdk1.8.0_171\jre\lib\jce.jar;C:\Program Files\Java\jdk1.8.0_171\jre\lib\jfr.jar;C:\Program Files\Java\jdk1.8.0_171\jre\lib\jfxswt.jar;C:\Program Files\Java\jdk1.8.0_171\jre\lib\jsse.jar;C:\Program Files\Java\jdk1.8.0_171\jre\lib\management-agent.jar;C:\Program Files\Java\jdk1.8.0_171\jre\lib\plugin.jar;C:\Program Files\Java\jdk1.8.0_171\jre\lib\resources.jar;C:\Program Files\Java\jdk1.8.0_171\jre\lib\rt.jar;E:\Workspaces\IdeaProjects\DemoTest\out\production\DemoTest" cn.yzstu.bulidermodule.FeeDemo
OrderNo:MOBL3a989c63-ce7f-4210-8193-adcab306929f
FeeType:SMS
Money:10.0
OrderNo:UNCd3504a9d-62a5-4fde-91a1-49e1d1df2b23
FeeType:SMS
Money:20.0
OrderNo:ABC33369090-2639-4653-82fa-f76fb397fa24
FeeType:Cash
Money:2.0
OrderNo:CMB845f2043-e297-49fd-b397-a061be5adf64
FeeType:Cash
Money:5.0

Process finished with exit code 0

10.組件變動

上面我們已經用Builder成功獲取到了我們想要的國內用戶的計費方式集,其中FeeType是組件中不常改動的地方,而計費私有的屬性則是我們經常改動的地方,比如我們現在想改動中國移動的計費點,直接在ChinaMobileFee中改動價格即可。

import java.util.UUID;

/**
 * 類描述
 *
 * @author: 12405
 * @date: 2020/3/25-22:49
 */
public class ChinaMobileFee extends SMSFee {

    @Override
    public String orderNo() {
        return "MOBL"+ UUID.randomUUID();
    }

    @Override
    public float price() {
        return 20.0f;//改動價格
    }
}
"C:\Program Files\Java\jdk1.8.0_171\bin\java.exe" "-javaagent:E:\tools\IntelliJ IDEA 2019.3.3\lib\idea_rt.jar=54431:E:\tools\IntelliJ IDEA 2019.3.3\bin" -Dfile.encoding=UTF-8 -classpath "C:\Program Files\Java\jdk1.8.0_171\jre\lib\charsets.jar;C:\Program Files\Java\jdk1.8.0_171\jre\lib\deploy.jar;C:\Program Files\Java\jdk1.8.0_171\jre\lib\ext\access-bridge-64.jar;C:\Program Files\Java\jdk1.8.0_171\jre\lib\ext\cldrdata.jar;C:\Program Files\Java\jdk1.8.0_171\jre\lib\ext\dnsns.jar;C:\Program Files\Java\jdk1.8.0_171\jre\lib\ext\jaccess.jar;C:\Program Files\Java\jdk1.8.0_171\jre\lib\ext\jfxrt.jar;C:\Program Files\Java\jdk1.8.0_171\jre\lib\ext\localedata.jar;C:\Program Files\Java\jdk1.8.0_171\jre\lib\ext\nashorn.jar;C:\Program Files\Java\jdk1.8.0_171\jre\lib\ext\sunec.jar;C:\Program Files\Java\jdk1.8.0_171\jre\lib\ext\sunjce_provider.jar;C:\Program Files\Java\jdk1.8.0_171\jre\lib\ext\sunmscapi.jar;C:\Program Files\Java\jdk1.8.0_171\jre\lib\ext\sunpkcs11.jar;C:\Program Files\Java\jdk1.8.0_171\jre\lib\ext\zipfs.jar;C:\Program Files\Java\jdk1.8.0_171\jre\lib\javaws.jar;C:\Program Files\Java\jdk1.8.0_171\jre\lib\jce.jar;C:\Program Files\Java\jdk1.8.0_171\jre\lib\jfr.jar;C:\Program Files\Java\jdk1.8.0_171\jre\lib\jfxswt.jar;C:\Program Files\Java\jdk1.8.0_171\jre\lib\jsse.jar;C:\Program Files\Java\jdk1.8.0_171\jre\lib\management-agent.jar;C:\Program Files\Java\jdk1.8.0_171\jre\lib\plugin.jar;C:\Program Files\Java\jdk1.8.0_171\jre\lib\resources.jar;C:\Program Files\Java\jdk1.8.0_171\jre\lib\rt.jar;E:\Workspaces\IdeaProjects\DemoTest\out\production\DemoTest" cn.yzstu.bulidermodule.FeeDemo
OrderNo:MOBLd3140a28-55a3-4cb4-8de8-ce32043a3833
FeeType:SMS
Money:20.0
OrderNo:UNCb562defd-287b-4957-9a2c-e12a782a616b
FeeType:SMS
Money:20.0
OrderNo:ABCc6b54887-f18a-4e8a-b060-7a3fe6015a07
FeeType:Cash
Money:2.0
OrderNo:CMB21663c63-9a66-4b99-9ade-d5d9659975d3
FeeType:Cash
Money:5.0

Process finished with exit code 0

五、總結

該模式的主要優點如下:

  1. 各個具體的建造者相互獨立,有利於系統的擴展。
  2. 客戶端不必知道產品內部組成的細節,便於控制細節風險。

其缺點如下:

  1. 產品的組成部分必須相同,這限制了其使用範圍。

  2. 如果產品的內部變化複雜,該模式會增加很多的建造者類。

建造者(Builder)模式和工廠模式的關注點不同:建造者模式注重零部件的組裝過程,而工廠方法模式更注重零部件的創建過程,但兩者可以結合使用。

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