Java基礎篇--設計模式

i18n486發表於2020-11-05

目錄

前言

設計模式

建立型模式

單例模式

工廠方法模式

抽象工廠模式

建造者模式

原型模式

結構型模式

介面卡模式

橋接模式

組合模式

裝飾模式

外觀模式

亨元模式

代理模式

行為型模式:

訪問者模式

模板模式

策略模式

狀態模式

觀察者模式

備忘錄模式

中介者模式

迭代器模式

直譯器模式

命令模式

責任鏈模式


前言

帶著問題學java系列博文之java基礎篇。從問題出發,學習java知識。


設計模式

設計模式(Design pattern)是一套被反覆使用、多數人知曉的、經過分類編目的、程式碼設計經驗的總結。使用設計模式是為了可重用程式碼,優雅快捷地實現特定需求。Java中共計總結出了23種設計模式,這些設計模式又主要分為三大類,分別是:建立型、行為型和結構型。

 

建立型模式

建立型模式:物件例項化的模式,建立型模式用於解耦物件的例項化過程。

單例模式

單例模式:用於物件例項化,保證全域性僅有一個物件例項,且執行緒同步。主要實現方式有:懶漢模式、餓漢模式、雙檢鎖模式以及靜態內部類模式,還包含一個特殊的實現方式,列舉類。下面的程式碼範例都一一實現了,並在註釋中分析了各個實現方式的優缺點。

/**
 * 單例模式
 */
public class Singleton {
    /*
    //懶漢模式
    private static Singleton mSingleton;

    private Singleton(){}

    public static Singleton getInstance(){
        if (mSingleton == null){
            mSingleton = new Singleton();
        }
        return mSingleton;
    }


    //餓漢模式
    private static Singleton mInstance = new Singleton();

    private Singleton(){}

    public static Singleton getmInstance(){
        return mInstance;
    }
    */
    //上面實現的兩種模式有很大的缺陷:
    //懶漢模式:優點是僅在使用的時候才初始化,減少記憶體佔用;但是存在併發同步危險;
    //餓漢模式:在一開始就初始化,佔用記憶體


    /*
    //改進的懶漢模式 dcl-雙檢鎖
    private static Singleton mInstance;

    private Singleton(){}

    public static Singleton getmInstance(){
        if (mInstance == null){
            synchronized (Singleton.class){
                if (mInstance == null){
                    mInstance = new Singleton();
                }
            }
        }
        return mInstance;
    }

    //改進之後的懶漢模式保證了同步,且減少了每次呼叫都需要同步的消耗。但是仍會存在小概率失敗(雙重檢查鎖定失效)
    */

    //靜態內部類方式
    private static Singleton mInstance;
    private Singleton(){}
    public static Singleton getmInstance(){
        return SingletonHolder.singleton;
    }
    private static class SingletonHolder{
        private static final Singleton singleton = new Singleton();
    }
    //這種方式既保證了執行緒同步,也保證了例項的唯一性,同時只有在使用時才會例項化,推薦使用這種方式。


    //實現單例的最佳方式:列舉
    public enum SinletonEnum{
        INSTANCE;
        public void otherMethods(){}
    }

    public enum Color{
        //新增引數的列舉
        RED(1),GREEN(2),BLACK(3);
        private int code;
        Color(int code){
            this.code = code;
        }

        public int getCode() {
            return code;
        }
    }
}

工廠方法模式

工廠方法模式屬於工廠模式的一類,將例項化物件的工作進行封裝,實現業務程式碼與物件例項化之間的解耦。類似現實生活中,要用到一個電器,則由電器工廠生產一個,我們直接從工廠拿就可以了,而不用關心如何生產。

簡單工廠模式(靜態工廠模式)屬於工廠方法模式的特例:

public abstract class BMW {
}

public class BMW520 extends BMW {
    public BMW520() {
        System.out.println("生產-》BMW520");
    }
}

public class BMW530 extends BMW {
    public BMW530() {
        System.out.println("生產-》bmw530");
    }
}

/**
 * 簡單工廠模式
 * 優點:實現簡單,程式碼邏輯清晰易懂
 * 缺點:工廠類不遵循開閉原則,每增加或者減少一個具體的產品類,都需要修改工廠類程式碼,增加case或者刪除case
 */
public class BMWFactory {
    public static BMW createBMW(int type){
        switch (type){
            case 520:
                return new BMW520();
            case 530:
                return new BMW530();
                default:
                    return null;
        }
    }

    public static void main(String[] args) {
        BMW bmw520 = BMWFactory.createBMW(520);
        BMW bmw530 = BMWFactory.createBMW(530);
    }
}

為了符合開閉原則,工廠方法模式對簡單工廠進行了擴充:

public abstract class BMW {
}

public class BMW520 extends BMW {
    public BMW520() {
        System.out.println("生產-》BMW520");
    }
}

public class BMW530 extends BMW {
    public BMW530() {
        System.out.println("生產-》bmw530");
    }
}

public interface BMWFactory {
    BMW createBMW();
}

public class BMW520Factory implements BMWFactory {
    @Override
    public BMW createBMW() {
        return new BMW520();
    }
}

public class BMW530Factory implements BMWFactory {
    @Override
    public BMW createBMW() {
        return new BMW530();
    }
}

/**
 * 工廠方法模式
 * 優點:實現簡單,程式碼邏輯清晰易理解,且遵循開閉原則(新增產品類,不需要改動已有程式碼,只需要按照工廠介面,實現一個具體的產品工廠即可)
 * 缺點:需要實現諸多的工廠類,隨著產品類的增多,工廠類也越來越多
 */
public class Customer {
    public static void main(String[] args) {
        BMW bmw520 = new BMW520Factory().createBMW();
        BMW bmw530 = new BMW530Factory().createBMW();
    }
}

抽象工廠模式

拿上面的例子繼續,BMW升級,加配空調、沙發,形成一個產品族。BMW520配置空調A和真皮沙發;BMW530配置空調B和布藝沙發。即抽象工廠區別於工廠方法模式是,抽象工廠模式是抽象工廠具有生產產品族的能力,由於具體的工程實現類實現生產一組特定的產品。

public abstract class AirConditioner {
}

public class AirConditionerA extends AirConditioner {
    public AirConditionerA() {
        System.out.println("生產空調A");
    }
}

public class AirConditionerB extends AirConditioner {
    public AirConditionerB() {
        System.out.println("生產空調B");
    }
}

public abstract class Sofa {
}

public class LeatherSofa extends Sofa {
    public LeatherSofa() {
        System.out.println("生產真皮沙發");
    }
}

public class ClothSofa extends Sofa {
    public ClothSofa() {
        System.out.println("生產布藝沙發");
    }
}

public interface BMWFactory {
    BMW createBMW();
    AirConditioner createAirConditioner();
    Sofa createSofa();
}

public class BMW520Factory implements BMWFactory {
    @Override
    public BMW createBMW() {
        createAirConditioner();
        createSofa();
        return new BMW520();
    }

    @Override
    public AirConditioner createAirConditioner() {
        return new AirConditionerA();
    }

    @Override
    public Sofa createSofa() {
        return new LeatherSofa();
    }
}

public class BMW530Factory implements BMWFactory {
    @Override
    public BMW createBMW() {
        createAirConditioner();
        createSofa();
        return new BMW530();
    }

    @Override
    public AirConditioner createAirConditioner() {
        return new AirConditionerB();
    }

    @Override
    public Sofa createSofa() {
        return new ClothSofa();
    }
}


/**
 * 抽象工廠模式
 * 由具體的工廠生產一組產品,對應特定的產品族
 */
public class Customer {
    public static void main(String[] args) {
        BMW bmw520 = new BMW520Factory().createBMW();
        BMW bmw530 = new BMW530Factory().createBMW();
    }
}

建造者模式

建造者模式(創造者模式):例項化具有多個引數,並且存在部分引數必須賦初值、部分引數可選賦值的物件時,相較於使用多個構造器或者使用javabean,是一種更優越的實現方式。比如,一臺小米電視,它有幾個引數必須初始化時設定:cpu引數、螢幕引數;有幾個引數可選:gpu引數、解析度、外設。簡單做法,可以寫多個構造器,引數列表從0到所有引數;或者可以寫一系列getter和setter,初始化之後,通過setter設定初值。這兩個方法都容易在使用的時候出錯,引數傳遞錯誤,遺漏某個屬性沒有setter等等。而使用建造者模式就可以很好的避免這些情況,對於必須賦初值的屬性,強制要求賦初值,對於可選的屬性,則提供可選設定方法。

/**
 * 建造者模式
 */
public class MiTV5 {
    private String cpu;
    private String screen;
    private String gpu;
    private String resolution;
    private String peripheral;

    private MiTV5(Builder builder) {
        cpu = builder.cpu;
        screen = builder.screen;
        gpu = builder.gpu;
        resolution = builder.resolution;
        peripheral = builder.peripheral;
    }

    public static class Builder{
        private String cpu;
        private String screen;
        private String gpu;
        private String resolution;
        private String peripheral;

        public Builder(String cpu, String screen) {
            this.cpu = cpu;
            this.screen = screen;
        }

        public Builder setGpu(String gpu){
            this.gpu = gpu;
            return this;
        }

        public Builder setResolution(String resolution){
            this.resolution = resolution;
            return this;
        }

        public Builder setPeripheral(String peripheral){
            this.peripheral = peripheral;
            return this;
        }

        public MiTV5 build(){
            return new MiTV5(this);
        }
    }



    @Override
    public String toString() {
        return "MiTV5{" +
                "cpu='" + cpu + '\'' +
                ", screen='" + screen + '\'' +
                ", gpu='" + gpu + '\'' +
                ", resolution='" + resolution + '\'' +
                ", peripheral='" + peripheral + '\'' +
                '}';
    }

    public static void main(String[] args) {
        MiTV5 miTV5 = new Builder("A53_4核", "65寸")
                .setGpu("MEMC運動補償")
                .setResolution("RGB3色真4K")
                .setPeripheral("贈送遊戲手柄")
                .build();
        System.out.println(miTV5.toString());
    }
}

 

原型模式

原型模式(物件深拷貝):直接拷貝已經存在於記憶體的例項物件,生成新的例項。適用於需要大量同一類物件的場景,直接拷貝的效率要高於new建立的效率;此外,例項物件的成員屬性大部分相同,只有少量屬性需要更改,使用拷貝可以減少賦值工作。(關於拷貝的知識,如果有所淡忘,可以查閱《Java基礎篇--拷貝》)

/**
 * 拷貝就是原型模式
 */
public class Resume implements Cloneable {
    private String name;
    private String selfEvaluation;
    private String salary;

    public Resume(String name, String selfEvaluation, String salary) {
        this.name = name;
        this.selfEvaluation = selfEvaluation;
        this.salary = salary;
    }

    @Override
    public Resume clone() throws CloneNotSupportedException {
        return (Resume) super.clone();
    }

    public void setSalary(String salary) {
        this.salary = salary;
    }

    @Override
    public String toString() {
        return "Resume:{name:'"+name+"',selfEvaluation:'"+selfEvaluation
                +"',salary:'"+salary+"'}";
    }

    public static void main(String[] args) {
        Resume resumeMuban = new Resume("張三"
                , "5年後臺深耕經驗,熟悉各大後臺框架,精通java,熟練使用各大元件,玩轉微服務"
                , "20K");
        try {
            Resume resume1 = resumeMuban.clone();
            resume1.setSalary("21K");
            Resume resume2 = resumeMuban.clone();
            resume2.setSalary("18k");
            Resume resume3 = resumeMuban.clone();
            resume3.setSalary("19K");
            System.out.println(resume1);
            System.out.println(resume2);
            System.out.println(resume3);
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
        }
    }
}

 

結構型模式

結構型模式:組合、封裝、裝飾類和物件,形成更豐富的用例。旨在複用類、擴充套件類、代理類等對已有類進行增強。

介面卡模式

某一類設計的方法已經不再適應新的系統,但我們又想繼續使用這個類的方法作為底層實現,此時就需要一個介面卡,實現對這個類的包裝。介面卡模式既可以作為類結構型模式,也可以作為物件結構型模式。使用介面卡模式的優點:不需要修改或者廢棄原有的功能類,只需要增加一個介面卡類,就可以繼續讓原有的功能類工作,加強了程式碼複用,且遵循開閉原則。比如:有一根Usb線,但是現在手機升級了,變成了TypeC介面,此時就需要一個轉換頭,讓我們可以繼續使用Usb線充電。

public class Usb {
    public void usbOutput(){
        System.out.println("usb輸出");
    }
}

public interface Usb2TypeC {
    void output();
}

/**
 * 介面卡模式
 * 類介面卡:子類繼承父類,可以直接呼叫父類方法
 * 物件介面卡:持有物件例項,通過物件例項呼叫物件成員方法
 */
/*
public class UsbTypeCAdapter extends Usb implements Usb2TypeC {

    @Override
    public void output() {
        super.usbOutput();
    }
}
*/

public class UsbTypeCAdapter implements Usb2TypeC {

    private Usb usb = new Usb();

    @Override
    public void output() {
        usb.usbOutput();
    }
}

 

橋接模式

橋接模式:將兩個維度橋接起來,兩個維度可以獨立變化,互不影響。橋接模式可以有效避免多層繼承,儘量遵循單一原則,極大的提供系統可擴充套件性。

例項:電腦銷售,我們常規想到的是建立一個抽象類computer,含有電腦的常規屬性和基本功能,設計抽象方法以供子類具體擴充套件。隨著市場發展,衍生出諸多品牌,此時我們只能是繼續建立諸多的品牌子類繼承computer,然後整個繼承鏈都被修改,導致層級越來越多,越來越難以維護。採用橋接模式設計,可以儘量分離出多個抽象類,降低繼承的層級,便於系統擴充套件。將品牌拆開來,brand和computer兩個頂層父類,縮短繼承鏈;而且各自都可以很方便的擴充套件,互不影響。

public abstract class Brand {
    public String name;

    public Brand(String name) {
        this.name = name;
    }

    public abstract void show();
}


public class Dell extends Brand {

    public Dell() {
        super("戴爾");
    }

    @Override
    public void show() {
        System.out.println("品牌:"+name);
    }
}

public class Lenovo extends Brand {

    public Lenovo() {
        super("聯想");
    }

    @Override
    public void show() {
        System.out.println("品牌:"+name);
    }
}

public abstract class Computer {
    protected Brand brand;

    public Computer(Brand brand) {
        this.brand = brand;
    }

    public void show(){
        brand.show();
    }
}

public class Desktop extends Computer {

    public Desktop(Brand brand) {
        super(brand);
    }

    @Override
    public void show() {
        super.show();
        System.out.println("品種:臺式電腦");
    }
}

public class Laptop extends Computer {

    public Laptop(Brand brand) {
        super(brand);
    }

    @Override
    public void show() {
        super.show();
        System.out.println("品種:筆記本");
    }
}

public class Customer {
    public static void main(String[] args) {
        Desktop desktop = new Desktop(new Lenovo());
        desktop.show();
        Laptop laptop = new Laptop(new Dell());
        laptop.show();
    }
}

 

組合模式

組合模式(Composite Pattern)將物件組合成樹形結構以表示“部分-整體”的層次結構。組合模式使得使用者可以使用一致的方法操作單個物件和組合物件。

比如:安徽大學擁有兩個校區,磬苑校區和龍河校區,每個校區都有各自的學院,共同組成了安徽大學。

public abstract class College {
    private String name;
    public College(String name) {
        this.name = name;
    }
    public String getName() {
        return name;
    }
}

public class EnglishCollege extends College {
    public EnglishCollege() {
        super("英語學院");
    }
}

public class SoftwareCollege extends College {
    public SoftwareCollege() {
        super("軟體學院");
    }
}

public class MathCollege extends College {
    public MathCollege() {
        super("數學學院");
    }
}

public class InternationalCollege extends College {
    public InternationalCollege() {
        super("國際學院");
    }
}

public abstract class Campus {
    protected List<College> collegeList = new LinkedList<>();
    public void addCollege(College college){
        collegeList.add(college);
    }
    public void removeCollege(College college){
        collegeList.remove(college);
    }
    public abstract void show();
}

public class QinyuanCampus extends Campus {
    public QinyuanCampus() {
        addCollege(new SoftwareCollege());
        addCollege(new EnglishCollege());
        addCollege(new MathCollege());
    }

    @Override
    public void show() {
        for (College college : collegeList) {
            System.out.println("磬苑校區:"+college.getName());
        }
    }
}

public class LongheCampus extends Campus {
    public LongheCampus() {
        addCollege(new EnglishCollege());
        addCollege(new InternationalCollege());
    }

    @Override
    public void show() {
        for (College college : collegeList) {
            System.out.println("龍河校區:"+college.getName());
        }
    }
}

public class AnHuiUniversity {
    private List<Campus> campusList = new LinkedList<>();

    public void addCampus(Campus campus){
        campusList.add(campus);
    }

    public void removeCampus(Campus campus){
        campusList.remove(campus);
    }
    
    public void show(){
        for (Campus campus : campusList) {
            campus.show();
        }
    }

    public static void main(String[] args) {
        AnHuiUniversity anHuiUniversity = new AnHuiUniversity();
        anHuiUniversity.addCampus(new QinyuanCampus());
        anHuiUniversity.addCampus(new LongheCampus());
        anHuiUniversity.show();
    }
}

 

裝飾模式

裝飾模式(Decorator),動態地給一個物件新增一些額外的職責,就增加功能來說,裝飾模式比生成子類更靈活。

public class Apple {
    public void showAppearance(){
        System.out.print("裸蘋果");
    }
}

public abstract class Decrator extends Apple {
    private Apple apple;

    public Decrator(Apple apple) {
        this.apple = apple;
    }

    @Override
    public void showAppearance() {
        if (null != apple){
            apple.showAppearance();
        }
    }
}

public class FoxconnDecrator extends Decrator {

    public FoxconnDecrator(Apple apple) {
        super(apple);
    }

    @Override
    public void showAppearance() {
        System.out.print("給‘");
        super.showAppearance();
        System.out.println("’貼上紅富士標籤");
    }
}

public class YantaiDecrator extends Decrator {
    public YantaiDecrator(Apple apple) {
        super(apple);
    }

    @Override
    public void showAppearance() {
        System.out.print("給‘");
        super.showAppearance();
        System.out.println("’貼上山東煙臺標籤");
    }
}

public class Test {
    public static void main(String[] args) {
        FoxconnDecrator foxconnDecrator = new FoxconnDecrator(new Apple());
        foxconnDecrator.showAppearance();
        YantaiDecrator yantaiDecrator = new YantaiDecrator(new Apple());
        yantaiDecrator.showAppearance();
    }
}

裝飾者模式就是對被裝飾者進行增強,比如上例對apple進行增強,多個不同的裝飾,就是多個裝飾者子類。

 

外觀模式

外觀模式(Facade),為子系統中的一組介面提供一個一致的介面,此模式定義了一個高層介面,這個介面使得這一子系統更加容易使用。隱藏底層細節,需要什麼功能只能通過門面介面開通,更加安全。

public class Lays {
    public void sale(){
        System.out.println("樂事做活動,買三送一");
    }
}

public class Yogurt {
    public void update(){
        System.out.println("君樂寶上新啦,全新芝士口味系列酸奶:芝士黴黴、芝士厚燒、芝士海鹽");
    }
}

public class Facade {
    private Lays lays;
    private Yogurt yogurt;

    public Facade(Lays lays, Yogurt yogurt) {
        this.lays = lays;
        this.yogurt = yogurt;
    }

    public void saleLays(){
        lays.sale();
    }

    public void updateYogurt(){
        yogurt.update();
    }

    public static void main(String[] args) {
        Facade facade = new Facade(new Lays(), new Yogurt());
        facade.saleLays();
        facade.updateYogurt();
    }
}

 

亨元模式

亨元模式:運用共享技術有效地支援大量細粒度的物件,池技術的重要實現方式。享元模式可以分成單純享元模式複合享元模式兩種形式,享元模式可以分成單純享元模式複合享元模式兩種形式。

單純享元模式所涉及到的角色如下:

  ●  抽象享元(Flyweight)角色 :給出一個抽象介面,以規定出所有具體享元角色需要實現的方法。

  ●  具體享元(ConcreteFlyweight)角色:實現抽象享元角色所規定出的介面。如果有內蘊狀態的話,必須負責為內蘊狀態提供儲存空間。

  ●  享元工廠(FlyweightFactory)角色 :本角色負責建立和管理享元角色。本角色必須保證享元物件可以被系統適當地共享。當一個客戶端物件呼叫一個享元物件的時候,享元工廠角色會檢查系統中是否已經有一個符合要求的享元物件。如果已經有了,享元工廠角色就應當提供這個已有的享元物件;如果系統中沒有一個適當的享元物件的話,享元工廠角色就應當建立一個合適的享元物件。

複合亨元模式相較於單純亨元模式,增加了一個複合亨元角色,然後在工廠類中增加了一個獲取複合亨元角色的方法。

public interface Flyweight {
    //一個示意性方法,引數state是外蘊狀態
    public void operation(String state);
}

public class ConcreteFlyweight implements Flyweight {
    private Character intrinsicState = null;
    /**
     * 建構函式,內蘊狀態作為引數傳入
     * @param state
     */
    public ConcreteFlyweight(Character state){
        this.intrinsicState = state;
    }
    
    
    /**
     * 外蘊狀態作為引數傳入方法中,改變方法的行為,
     * 但是並不改變物件的內蘊狀態。
     */
    @Override
    public void operation(String state) {
        System.out.println("Intrinsic State = " + this.intrinsicState);
        System.out.println("Extrinsic State = " + state);
    }
}

public class FlyweightFactory {
    private Map<Character,Flyweight> files = new HashMap<Character,Flyweight>();
    
    public Flyweight factory(Character state){
        //先從快取中查詢物件
        Flyweight fly = files.get(state);
        if(fly == null){
            //如果物件不存在則建立一個新的Flyweight物件
            fly = new ConcreteFlyweight(state);
            //把這個新的Flyweight物件新增到快取中
            files.put(state, fly);
        }
        return fly;
    }
}

public class Client {

    public static void main(String[] args) {
        FlyweightFactory factory = new FlyweightFactory();
        Flyweight fly = factory.factory(new Character('a'));
        fly.operation("First Call");
        
        fly = factory.factory(new Character('b'));
        fly.operation("Second Call");
        
        fly = factory.factory(new Character('a'));
        fly.operation("Third Call");
    }
}

 

代理模式

代理模式給某一個物件提供一個代理物件,並由代理物件控制對原物件的引用,對原物件進行增強。通俗的來講代理模式就是我們生活中常見的中介。Java中常見的有三種代理模式:靜態代理、動態代理——依賴jdk的api實現和依賴cglib實現。

靜態代理:實現具體子類,增強被代理物件。

public interface Lenovo {
    String sale(double price);
    String show();
}

public class LenovoHome implements Lenovo {
    @Override
    public String sale(double price) {
        return String.format("花了%s元在聯想原廠買了一臺Lenovo電腦",price);
    }

    @Override
    public String show() {
        return "展示電腦:效能超強,視訊記憶體極大,固態,液冷!!!";
    }
}

public class HefeiLenovo implements Lenovo {

    private LenovoHome lenovoHome;

    public HefeiLenovo(LenovoHome lenovoHome) {
        this.lenovoHome = lenovoHome;
    }

    @Override
    public String sale(double price) {
        System.out.println("合肥代理店進貨,"+lenovoHome.sale(price*0.85));
        return String.format("客戶實際花了%s元在合肥聯想代理店買了一臺電腦",price);
    }

    @Override
    public String show() {
        return "展示電腦:效能超強,視訊記憶體極大,固態,液冷!!!外送原廠滑鼠,鍵盤";
    }
}

動態代理:基於JDK Api實現(基於介面的動態代理)

    /**
     * 基於介面的動態代理(基於子類的動態代理需要依賴jar包cglib實現)
     * 動態代理:動態代理,記憶體中是沒有具體的代理類,而是在具體執行時動態生成的
     * 利用Proxy.newProxyInstance靜態方法得到動態代理物件
     * 在invoke中可以對具體的方法進行增強
     * 1.對引數增強:獲取到引數,對引數進行處理之後,再作為執行方法的入參
     * 2.對方法體增強:在實體類執行方法前後,可以新增想要執行的邏輯
     * 3.對返回值增強:在實體類方法執行後,獲取到返回值,進行處理之後,再返回給呼叫者
     *
     * 使用動態代理物件執行方法,此時就會得到增強後的結果
     */
    public static void testDynamicProxy(){
        Lenovo lenovo = new LenovoHome();
        Lenovo proxy_lenovo = (Lenovo) Proxy.newProxyInstance(LenovoHome.class.getClassLoader(), LenovoHome.class.getInterfaces(), new InvocationHandler() {
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                if (method.getName().equals("sale")){
                    //對sale方法進行增強
                    double price = (double) args[0]*1.25;//對引數增強
                    System.out.println("專車接送,直達店面");//對方法體增強
                    Object result = method.invoke(lenovo, price);//使用lenovohome物件執行具體方法,引數已經被改變
                    System.out.println("免費送貨到家");//對方法體增強
                    return result+",免費贈送原廠滑鼠+鍵盤";//對返回值增強
                } else {
                    Object invoke = method.invoke(lenovo, args);
                    return invoke;
                }
            }
        });

        String sale = proxy_lenovo.sale(8000);
        System.out.println(sale);
        System.out.println(proxy_lenovo.show());
    }

動態代理:基於cglib庫實現(基於子類的動態代理),需要依賴cglib jar(spring-core 3.2版本之後,就引入了cglib,所以maven專案可以直接引入spring-core依賴即可)

public class Lenovo {
    public String sale(double price){
        return "花了"+price+"元買了一臺電腦";
    }

    public String show(){
        return "展示電腦:效能超強,視訊記憶體極大,固態,液冷!!!";
    }
}

public class ProxyFactory implements MethodInterceptor {

    //被代理物件
    private Object target;

    public ProxyFactory(Object target) {
        this.target = target;
    }

    //給被代理物件建立一個代理
    public Object getProxyInstance(){
        //工具類
        Enhancer enhancer = new Enhancer();
        //設定被代理父類
        enhancer.setSuperclass(target.getClass());
        //設定回撥
        enhancer.setCallback(this);
        //建立代理
        return enhancer.create();
    }

    @Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        if (method.getName().equals("sale")){
            //對sale方法進行增強
            double price = (double) objects[0]*1.25;//對引數增強
            System.out.println("專車接送,直達店面");//對方法體增強
            Object result = method.invoke(target, price);//使用target物件執行具體方法,引數已經被改變
            System.out.println("免費送貨到家");//對方法體增強
            return result+",免費贈送原廠滑鼠+鍵盤";//對返回值增強
        } else {
            Object invoke = method.invoke(target, objects);
            return invoke;
        }
    }
}

public class Customer {
    public static void main(String[] args) {
        Lenovo lenovo = new Lenovo();
        Lenovo proxy = (Lenovo) new ProxyFactory(lenovo).getProxyInstance();
        System.out.println(proxy.sale(8000));
        System.out.println(proxy.show());
    }
}

 

行為型模式:

用來識別物件之間的常用交流模式並加以實現,如此,可在進行這些交流活動時增強彈性。

訪問者模式

訪問者模式是一種將資料操作和資料結構分離的設計模式。

// 員工基類
public abstract class Staff {

    public String name;
    public int kpi;// 員工KPI

    public Staff(String name) {
        this.name = name;
        kpi = new Random().nextInt(10);
    }
    // 核心方法,接受Visitor的訪問
    public abstract void accept(Visitor visitor);
}

// 工程師
public class Engineer extends Staff {

    public Engineer(String name) {
        super(name);
    }

    @Override
    public void accept(Visitor visitor) {
        visitor.visit(this);
    }
    // 工程師一年的程式碼數量
    public int getCodeLines() {
        return new Random().nextInt(10 * 10000);
    }
}

// 經理
public class Manager extends Staff {

    public Manager(String name) {
        super(name);
    }

    @Override
    public void accept(Visitor visitor) {
        visitor.visit(this);
    }
    // 一年做的產品數量
    public int getProducts() {
        return new Random().nextInt(10);
    }
}

public interface Visitor {

    // 訪問工程師型別
    void visit(Engineer engineer);

    // 訪問經理型別
    void visit(Manager manager);
}

// CEO訪問者
public class CEOVisitor implements Visitor {
    @Override
    public void visit(Engineer engineer) {
        System.out.println("工程師: " + engineer.name + ", KPI: " + engineer.kpi);
    }

    @Override
    public void visit(Manager manager) {
        System.out.println("經理: " + manager.name + ", KPI: " + manager.kpi +
                ", 新產品數量: " + manager.getProducts());
    }
}

public class CTOVisitor implements Visitor {
    @Override
    public void visit(Engineer engineer) {
        System.out.println("工程師: " + engineer.name + ", 程式碼行數: " + engineer.getCodeLines());
    }

    @Override
    public void visit(Manager manager) {
        System.out.println("經理: " + manager.name + ", 產品數量: " + manager.getProducts());
    }
}

// 員工業務報表類
public class BusinessReport {

    private List<Staff> mStaffs = new LinkedList<>();

    public BusinessReport() {
        mStaffs.add(new Manager("經理-A"));
        mStaffs.add(new Engineer("工程師-A"));
        mStaffs.add(new Engineer("工程師-B"));
        mStaffs.add(new Engineer("工程師-C"));
        mStaffs.add(new Manager("經理-B"));
        mStaffs.add(new Engineer("工程師-D"));
    }

    /**
     * 為訪問者展示報表
     * @param visitor 公司高層,如CEO、CTO
     */
    public void showReport(Visitor visitor) {
        for (Staff staff : mStaffs) {
            staff.accept(visitor);
        }
    }
}

public class Client {

    public static void main(String[] args) {
        // 構建報表
        BusinessReport report = new BusinessReport();
        System.out.println("=========== CEO看報表 ===========");
        report.showReport(new CEOVisitor());
        System.out.println("=========== CTO看報表 ===========");
        report.showReport(new CTOVisitor());
    }
}

如上例:某公司年底計算績效,主要由CEO和CTO來確定,員工主要有兩類:工程師、產品經理。其中CEO主要關注工程師的KPI以及產品經理kpi和新產品數量,CTO主要關注工程師的程式碼量以及產品經理的新產品數量。用訪問者模式設計:員工抽象類(staff,定義核心方法accept(Visitor)),具體的員工類繼承員工抽象類(工程師:Enginner,產品經理:Manager);員工類相當於資料結構,用一個accept(Visitor)方法分離資料操作,具體的資料操作放到Visitor中去。訪問者介面類:Visitor(定義visit方法),具體的訪問者實現類實現Visitor介面(CEOVisitor和CTOVisitor),在具體的訪問者類中實現具體的資料操作邏輯。統一的資料集合——報表類(BusinessReport),持有資料集,以及提供遍歷運算元據的入口。

 

模板模式

 定義一個操作中演算法的骨架,而將一些步驟延遲到子類中,模板方法使得子類可以不改變演算法的結構即可重定義該演算法的某些特定步驟。

/**
 * 專案模板
 * 定義做專案的方法:規定具體步驟和順序
 * 步驟的具體實現交給具體專案實體類
 */
public abstract class ProjectTemplate {

    //做專案主要有三個步驟:資料庫設計、框架設計、編碼
    public void doProject(){
        this.doDataBaseDesign();
        this.doFrameworkDesign();
        this.doEncoding();
    }

    public abstract void doDataBaseDesign();

    public abstract void doFrameworkDesign();

    public abstract void doEncoding();
}

public class UserManagerProject extends ProjectTemplate {
    @Override
    public void doDataBaseDesign() {
        System.out.println("設計使用者管理系統資料庫");
    }

    @Override
    public void doFrameworkDesign() {
        System.out.println("進行使用者管理系統框架設計");
    }

    @Override
    public void doEncoding() {
        System.out.println("編碼實現使用者管理系統");
    }
}

public class SpeechRecognizeProject extends ProjectTemplate {
    @Override
    public void doDataBaseDesign() {
        System.out.println("設計語音識別系統的資料庫");
    }

    @Override
    public void doFrameworkDesign() {
        System.out.println("進行語音識別系統框架設計");
    }

    @Override
    public void doEncoding() {
        System.out.println("語音識別系統編碼實現");
    }
}

public class DevelopmentGroup {

    public static void main(String[] args) {
        System.out.println("----------------研發團隊做的第一個專案");
        ProjectTemplate project = new UserManagerProject();
        project.doProject();

        System.out.println("----------------研發團隊做的第二個專案");
        ProjectTemplate project2 = new SpeechRecognizeProject();
        project2.doProject();
    }
}

 

策略模式

定義了一組演算法,將每個演算法都封裝起來,並且使它們之間可以互換。

public abstract class Strategy {
    public abstract void operate();
}

public class StrategyA extends Strategy {
    @Override
    public void operate() {
        System.out.println("A策略具體操作");
    }
}

public class StrategyB extends Strategy {
    @Override
    public void operate() {
        System.out.println("B策略具體操作");
    }
}


public class Context {
    private Strategy strategy;

    public Context(Strategy strategy) {
        this.strategy = strategy;
    }

    public void contextDo(){
        strategy.operate();
    }
}

public class Test {
    public static void main(String[] args) {
        Context context = new Context(new StrategyA());
        context.contextDo();

        Context context1 = new Context(new StrategyB());
        context1.contextDo();
    }
}

 

狀態模式

當一個物件的內在狀態改變時允許改變其行為,這個物件看起來像是改變了其類。狀態模式主要解決的是當控制一個物件狀態的條件表示式過於複雜時的情況。把狀態的判斷邏輯轉移到表示不同狀態的一系列類中,可以把複雜的判斷邏輯簡化。

public abstract class State {

    public abstract void Handle(Context context);
}

public class ConcreteStateA extends State{
    @Override
    public void Handle(Context context) {
        context.setState(new ConcreteStateB()); //設定A的下一個狀態是B
    }
}

public class ConcreteStateB extends State{
    @Override
    public void Handle(Context context) {
        context.setState(new ConcreteStateA()); //設定B的下一個狀態是A
    }
}

public class Context {
    State state;
 
    public Context(State state) { //定義Context的初始狀態
        super();
        this.state = state;
    }
 
    public State getState() {
        return state;
    }
 
    public void setState(State state) {
        this.state = state;
        System.out.println("當前狀態為"+state);
    }
    public void request(){
        state.Handle(this); //對請求做處理並且指向下一個狀態
    }
}

public class Test {
    public static void main(String[] args) {
        Context context = new Context(new ConcreteStateA());
        System.out.println(context.getState());
        context.request();
    }
}

上例是不是很像工作流系統。

 

觀察者模式

觀察者模式(Observer),又叫釋出-訂閱模式(Publish/Subscribe),定義物件間一種一對多的依賴關係,使得每當一個物件改變狀態,則所有依賴於它的物件都會得到通知並自動更新。

模擬炒股:一隻股票Stock,一個股民Investor購買該股票,並訂閱關注該股票漲跌;股票發生大幅漲跌時,就會自動通知股民。

public abstract class Subject {
    private CopyOnWriteArrayList<Observer> observerList = new CopyOnWriteArrayList<>();

    public void registor(Observer observer){
        observerList.add(observer);
    }

    public void cancel(Observer observer){
        observerList.remove(observer);
    }

    public void notifyObservers(){
        for (Observer observer : observerList) {
            observer.update();
        }
    }
}

public class Stock extends Subject {
    private double increase = 0.0;

    public double getIncrease(){
        return increase;
    }

    public void change(){
        double now = new Random().nextDouble();
        double limit = now - increase;
        if (limit > 0.3 || limit < -0.3){
            increase = limit;
            notifyObservers();
        }
    }
}

public interface Observer {
    void update();
}

public class Investor implements Observer {

    private Stock stock;

    public Investor(Stock stock) {
        this.stock = stock;
        stock.registor(this::update);
    }

    @Override
    public void update() {
        double increase = stock.getIncrease();
        if (increase > 0){
            System.out.println("哈哈,股票大漲啊,漲幅:"+increase);
        } else {
            System.out.println("完了,傾家蕩產了,我要去天台,別攔我!"+increase);
        }
    }
}

public class SpeculateStocks {
    public static void main(String[] args) throws InterruptedException {
        //生成一隻股票
        Stock stock = new Stock();
        //模擬一個股民購買了該股票,並時刻關注股票的漲跌情況
        new Investor(stock);
        while (true){
            //模擬每天股票漲跌
            stock.change();
            Thread.sleep(40);
        }

    }
}

 

備忘錄模式

備忘錄模式(Memento),在不破壞封裝性的前提下,捕獲一個物件的內部狀態,並在該物件之外儲存著這個狀態。這樣以後就可將該物件恢復到原先儲存的狀態。

備忘錄模式主要有三個角色:發起人Originator,負責發起一個初始狀態的事務以及基於自身狀態建立備忘錄;備忘錄Memento,負責記錄事務的狀態;備忘錄管理者Creataker,負責儲存備忘錄。

public class Originator {

    private String state;

    public void setState(String state) {
        this.state = state;
    }

    public Memento createMento() {
        return (new Memento(state));
    }

    public void setMemento(Memento memento) {
        this.state = memento.getState();
    }

    public void show() {
        System.out.println("state = " + state);
    }

}

public class Memento {

    private String state;

    public Memento(String state) {
        this.state = state;
    }

    public String getState() {
        return state;
    }

}

public class Caretaker {

    private Memento memento;

    public Memento getMemento() {
        return memento;
    }

    public void setMemento(Memento memento) {
        this.memento = memento;
    }

}

public class Client {

    public static void main(String[] args) {
        //發起人設定初始狀態
        Originator originator = new Originator();
        originator.setState("On");    //Originator初始狀態
        originator.show();

        //備忘錄管理者儲存發起人基於自身此刻狀態建立的備忘錄
        Caretaker caretaker = new Caretaker();
        caretaker.setMemento(originator.createMento());

        //發起人改變狀態
        originator.setState("Off");    //Originator狀態變為Off
        originator.show();

        //發起人通過備忘錄管理者儲存的備忘錄恢復自身的狀態
        originator.setMemento(caretaker.getMemento());    //回覆初始狀態
        originator.show();
    }

}

 

中介者模式

同事類之間相互耦合,相互影響,為了可減少耦合,分開這種影響,所以引入了中介者模式。同事類就是互相持有對方,並且當自身發生變化時會影響對方也隨著改變的類。

中介者模式是一種比較常用的模式,也是一種比較容易被濫用的模式。對於大多數的情況,同事類之間的關係不會複雜到混亂不堪的網狀結構,因此,大多數情況下,將物件間的依賴關係封裝的同事類內部就可以的,沒有必要非引入中介者模式。

舉例:當一個同事類A改變時,同事類B也跟著改變;同事類B改變時同事類A也隨之改變。此時如果不使用中介者模式,那就是A和B互相持有對方例項,在自身改變時,通過對方的例項引用來改變對方,存在著嚴重的耦合。引入中介者模式,則可以消除耦合,A和B所有的改變都由中介者來操作。

public abstract class Colleagues {
    protected int number;

    public abstract void change(int number,Mediator mediator);
}

public class ColleaguesA extends Colleagues{

    @Override
    public void change(int number,Mediator mediator) {
        this.number = number;
        mediator.AModifyB();
    }
}

public class ColleaguesB extends Colleagues {
    @Override
    public void change(int number, Mediator mediator) {
        this.number = number;
        mediator.BModifyA();
    }
}

public abstract class Mediator {

    protected Colleagues colleaguesA;
    protected Colleagues colleaguesB;

    public Mediator(Colleagues colleaguesA, Colleagues colleaguesB) {
        this.colleaguesA = colleaguesA;
        this.colleaguesB = colleaguesB;
    }

    public abstract void AModifyB();

    public abstract void BModifyA();
}

public class ABMediator extends Mediator {
    public ABMediator(Colleagues colleaguesA, Colleagues colleaguesB) {
        super(colleaguesA, colleaguesB);
    }

    @Override
    public void AModifyB() {
        colleaguesB.number = colleaguesA.number*100;
        System.out.println("A:"+colleaguesA.number+",B:"+colleaguesB.number);
    }

    @Override
    public void BModifyA() {
        colleaguesA.number = colleaguesB.number/100;
        System.out.println("B:"+colleaguesB.number+",A:"+colleaguesA.number);
    }
}

public class Test {
    public static void main(String[] args) {
        Colleagues A = new ColleaguesA();
        Colleagues B = new ColleaguesB();
        ABMediator abMediator = new ABMediator(A, B);
        A.change(10,abMediator);
        System.out.println("---------------");
        B.change(2000,abMediator);
    }
}

 

迭代器模式

迭代器模式提供一種方法順序訪問一個聚合物件中的各個元素,而又不暴露其內部的表示。集合中常用的遍歷就是通過迭代器實現。Java為迭代器模式還建立了迭代器介面。

public class MenuItem {

    private String name;
    private double price;

    public MenuItem(String name, double price) {
        this.name = name;
        this.price = price;
    }
    
    @Override
    public String toString() {
        return "MenuItem{" +
                "name='" + name + '\'' +
                ", price=" + price +
                '}';
    }
}

public interface Menu {
    Iterator<MenuItem> createIterator();
}

public class KFCMenu implements Menu {
    private List<MenuItem> menuItems = new ArrayList<>();

    public KFCMenu() {
        menuItems.add(new MenuItem("烤翅",9.8));
        menuItems.add(new MenuItem("薯條",7.9));
        menuItems.add(new MenuItem("漢堡",8.5));
        menuItems.add(new MenuItem("可樂",5.6));
        menuItems.add(new MenuItem("上校雞塊",6.3));
    }

    @Override
    public Iterator<MenuItem> createIterator() {
        return new KFCMenuIterator(menuItems);
    }
}

public class KFCMenuIterator implements Iterator<MenuItem> {
    private List<MenuItem> menuItems;
    private int position = 0;

    public KFCMenuIterator(List<MenuItem> menuItems) {
        this.menuItems = menuItems;
    }

    @Override
    public boolean hasNext() {
        if (position < menuItems.size()){
            return true;
        }
        return false;
    }

    @Override
    public MenuItem next() {
        return menuItems.get(position++);
    }
}

public class Customer {
    public static void main(String[] args) {
        KFCMenu kfcMenu = new KFCMenu();
        Iterator<MenuItem> iterator = kfcMenu.createIterator();
        while (iterator.hasNext()){
            System.out.println(iterator.next().toString());
        }
    }
}

 

直譯器模式

直譯器模式:給定一個語言,定義它的文法得一種表示,並定義一個直譯器,這個直譯器使用該表示來解釋語言中的句子。

比如本例:輸入“down run 10”,經過直譯器執行後,轉換為“向下奔跑10”。

public abstract class AbstractNode {
	public abstract String interpret();
}

public class DirectionNode extends AbstractNode {
	private String direction;
	public DirectionNode(String dir) {
		this.direction=dir;
	}
	@Override
	public String interpret() {
		if(direction.equalsIgnoreCase("up")) {
			return "向上";
		}else if(direction.equalsIgnoreCase("down")) {
			return "向下";
		}else if(direction.equalsIgnoreCase("left")) {
			return "向左";
		}else if(direction.equalsIgnoreCase("right")) {
			return "向右";
		}else {
			return "無效指令";
		}
	}
}

public class ActionNode extends AbstractNode {
	private String action;
	public ActionNode(String a) {
		this.action=a;
	}
	@Override
	public String interpret() {
		if(action.equalsIgnoreCase("move")) {
			return "移動";
		}else if(action.equalsIgnoreCase("run")) {
			return "奔跑";
		}else {
		return "無效指令";
		}
	}
}

public class DistanceNode  extends AbstractNode{
	private String distance;
	public DistanceNode(String d) {
		this.distance=d;
	}
	@Override
	public String interpret() {
		return distance;
	}
}

public class SentenceNode extends AbstractNode{
	private AbstractNode direction;
	private AbstractNode action;
	private AbstractNode distanc;
 
	public SentenceNode(AbstractNode direc,AbstractNode a,AbstractNode d) {
		this.direction=direc;
		this.action=a;
		this.distanc=d;
	}
	@Override
	public String interpret() {
		return direction.interpret()+action.interpret()+distanc.interpret();
	}
}

public class InstructionHandler {
	private AbstractNode node;

	public void Handle(String instruction) {
		//用棧來儲存語法樹。
		AbstractNode left=null;
		AbstractNode direction=null,action=null,distance=null;
		Stack<AbstractNode> stack = new Stack<AbstractNode>();
		
		//用空格分隔指令
		String[] word = instruction.split(" ");
		//迴圈
		for(int i=0;i<word.length;i++) {
			String word1 = word[i];
			direction = new DirectionNode(word1);
			String word2 = word[++i];
			action = new ActionNode(word2);
			String word3 = word[++i];
			distance = new DistanceNode(word3);
			left= new SentenceNode(direction, action, distance);
			stack.push(left);
		}
		this.node=(AbstractNode)stack.pop();
	}
	
	public String output() {
		String result = node.interpret();
		return result;
	}
}

public class Client {
	public static void main(String[] args) {
		String instruction ="down run 10";
		InstructionHandler iHandler = new InstructionHandler();
		iHandler.Handle(instruction);
		String outString =iHandler.output();
		System.out.println(outString);
	}
}

 

命令模式

命令模式設計模式屬於行為型模式,將一個請求封裝成一個物件,從而讓你使用不同的請求把客戶端引數化,對請求排隊或者記錄請求日誌,可以提供命令的撤銷和恢復功能。

舉例:一個擁有十個可程式設計按鈕的遙控器,每個按鈕可以設定一個具體的動作,且可以撤銷執行。我們現在對這個遙控器進行程式設計,設定0號按鈕控制家裡的電燈開啟,1號按鈕控制電燈關閉。

public interface Command {
    void execute();
    void cancel();
}

public class NoCommand implements Command {
    @Override
    public void execute() {}

    @Override
    public void cancel() {}
}

public class LightOn implements Command {
    private LightReceiver lightReceiver;

    public LightOn(LightReceiver lightReceiver) {
        this.lightReceiver = lightReceiver;
    }

    @Override
    public void execute() {
        lightReceiver.on();
    }

    @Override
    public void cancel() {
        lightReceiver.off();
    }
}

public class LightOff implements Command {
    private LightReceiver lightReceiver;

    public LightOff(LightReceiver lightReceiver) {
        this.lightReceiver = lightReceiver;
    }

    @Override
    public void execute() {
        lightReceiver.off();
    }

    @Override
    public void cancel() {
        lightReceiver.on();
    }
}

public class LightReceiver {
    public void on(){
        System.out.println("開啟電燈");
    }

    public void off(){
        System.out.println("關閉電燈");
    }
}

public class RemoteController {
    private List<Command> commands = new ArrayList<>(10);

    public RemoteController() {
        for (int i = 0; i < 10; i++) {
            commands.add(new NoCommand());
        }
    }

    public void setCommand(int index,Command command){
        commands.set(index,command);
    }

    public void down(int index){
        commands.get(index).execute();
    }

    public void cancel(int index){
        commands.get(index).cancel();
    }
}

public class User {
    public static void main(String[] args) {
        RemoteController remoteController = new RemoteController();
        LightReceiver lightReceiver = new LightReceiver();
        remoteController.setCommand(0,new LightOn(lightReceiver));
        remoteController.setCommand(1,new LightOff(lightReceiver));

        remoteController.down(1);
        remoteController.down(0);
    }
}

 

責任鏈模式

責任鏈模式:使多個物件都有機會處理同一個請求,從而避免請求的傳送者和接收者之間的耦合關係。將這些物件連成一條鏈,並沿著這條鏈傳遞該請求,直到有一個物件處理它為止。

舉例:雙十一顧客去商場買東西,申請折扣;銷售員能直接批准的是5個點,經理是30個點,CEO是50個點。當顧客向銷售員申請折扣的時候,銷售員會根據折扣大小去處理,如果在其許可權範圍內,則直接批准,否則向上級領導提交申請,由領導審批,依次逐級下去,直到有一個人處理了該申請。

public abstract class PriceHandler {
    protected PriceHandler superior;

    public PriceHandler(PriceHandler superior) {
        this.superior = superior;
    }

    public abstract void processDiscount(double discount);
}


public class Salesman extends PriceHandler {

    public Salesman(PriceHandler superior) {
        super(superior);
    }

    @Override
    public void processDiscount(double discount) {
        if (discount < 0.05){
            System.out.format("%s批准了折扣 %.2f\n",this.getClass().getName(),discount);
        } else {
            superior.processDiscount(discount);
        }
    }
}

public class Manager extends PriceHandler {

    public Manager(PriceHandler superior) {
        super(superior);
    }

    @Override
    public void processDiscount(double discount) {
        if (discount <= 0.3){
            System.out.format("%s批准了折扣 %.2f\n",this.getClass().getName(),discount);
        } else {
            superior.processDiscount(discount);
        }
    }
}

public class CEO extends PriceHandler {

    public CEO(PriceHandler superior) {
        super(superior);
    }

    @Override
    public void processDiscount(double discount) {
        if (discount <= 0.5){
            System.out.format("%s批准了折扣 %.2f\n",this.getClass().getName(),discount);
        } else {
            System.out.format("很抱歉,這個%.2f折扣我們做不了",discount);
        }
    }
}

public class Customer {
    public static void main(String[] args) {
        CEO ceo = new CEO(null);
        Manager manager = new Manager(ceo);
        Salesman salesman = new Salesman(manager);
        System.out.println("顧客1向銷售員申請7折優惠");
        salesman.processDiscount(0.3);
        System.out.println("顧客2向銷售員申請4折優惠");
        salesman.processDiscount(0.6);
    }
}

 

 


以上繫個人理解,如果存在錯誤,歡迎大家指正。原創不易,轉載請註明出處!

相關文章