[design pattern](3) Dectorator

前言

好久沒有寫關於設計模式的博客了,實在是沒有太多的精力去寫。但我的以爲設計模式在咱們的平常開發中仍是挺重要的,它提升了軟件的可維護性。所以仍是有必要堅持學習設計模式,寫博客主要是爲了加深我對設計模式的理解。今天我要講的設計模式是裝飾者模式(Dectorator),它是結構型模式的一員。若是有什麼講的不正確的地方,但願各位大佬指正。java

 

思考題

首先,讓咱們思考下面的問題:設計模式

有這麼一家奶茶店,但願開發一個計算奶茶價格的軟件,當客戶點一杯奶茶,而且加入某幾樣配料時,須要及時的計算出這杯奶茶的價格,下面是奶茶和配料的價格。
原味奶茶:10
珍珠:2
椰果:3
巧克力:5

例子:若是用戶點椰果奶茶,那麼他的價格就是 原味奶茶+椰果=13。

當沒有學習過裝飾者模式時,我會給出下面的解決思路:ide

 Ingredient.java:學習

public interface Ingredient {
    Integer price();
}

 

配料接口:全部的配料都要實現這個接口,該接口有一個價格方法。this

 

Chocolate.java:spa

public class Chocolate implements Ingredient {
    public Integer price() {
        return 5;
    }
}
 

Coconut.java:設計

public class Coconut implements Ingredient {
    public Integer price() {
        return 3;
    }
}

 

 Pearl.java:code

public class Pearl implements Ingredient {
    public Integer price() {
        return 2;
    }
}

 

以上的上個人配料的實現類,他們都實現了 Ingredient 接口,而且實現了 price 方法。對象

 

MilkTea.java:blog

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

public class MilkTea {
    private List<Ingredient> ingredientList = new ArrayList<>();

    public void addIngredient(Ingredient ingredient) {
        ingredientList.add(ingredient);
    }

    public Integer countPrice() {
        Integer allPrice = 10;
        for (Ingredient ingredient : ingredientList) {
            allPrice += ingredient.price();
        }
        return allPrice;
    }
}

 

以上是奶茶類的實現,裏面有一個 ingredientList 成員變量,使用 addIngredient 就能夠增長配料,調用 countPrice 計算奶茶的價格。

 

TestMain.java:

public class TestMain {
    public static void main(String... args) {
        MilkTea milkTea = new MilkTea();
        milkTea.addIngredient(new Chocolate());
        System.out.println("巧克力奶茶:" + milkTea.countPrice());

        MilkTea milkTea_1 = new MilkTea();
        milkTea_1.addIngredient(new Coconut());
        milkTea_1.addIngredient(new Pearl());
        System.out.println("珍珠椰果奶茶:" + milkTea_1.countPrice());
    }
}

下面給出該實現的uml類圖。

 

裝飾者設計模式

定義:動態的給特定對象賦予新的功能.

類圖:

從上面的類圖咱們能夠總結出如下幾點:

1.實現裝飾者模式,咱們須要有一個公共接口,咱們的裝飾者和被裝飾者都須要繼承這個接口.

2.爲了更好地維護代碼,上面將被裝飾者的公共的代碼提取到了父類中,子類經過繼承這個父類能夠很容易的實現不一樣的特性.

3.在父類的接口中實現了 Material 接口,以保證裝飾者能夠被其餘裝飾者裝飾.

4.父類中有成員變量 Material ,以保證每一個裝飾者都知道本身裝飾的是什麼對象.

 重構思考題

Material.java:

public interface Material {
    Integer price();
}

 

 

MilkTea.java:

public class MilkTea implements Material {
    @Override
    public Integer price() {
        return 10;
    }
}

 

 

Ingredient.java:

public abstract class Ingredient implements Material {
    private Material material;
    
    public Ingredient(Material material) {
        this.material = material;
    }
    
    @Override
    public Integer price() {
        return material.price() + getPrice();
    }
    
    public abstract Integer getPrice();
}

 

 

Chocolate.java:

public class Chocolate extends Ingredient {
    public Chocolate(Material material) {
        super(material);
    }
    
    @Override
    public Integer getPrice() {
        return 5;
    }
}

 

 

Coconut.java:

public class Coconut extends Ingredient {
    public Coconut(Material material) {
        super(material);
    }
    @Override
    public Integer getPrice() {
        return 3;
    }
}

 

 

Pearl.java:

public class Pearl extends Ingredient {
    public Pearl(Material material) {
        super(material);
    }
    
    @Override
    public Integer getPrice() {
        return 2;
    }
}

 

 

MainTest.java:

public class MainTest {
    public static void main(String... args) {
        Material milkTea = new Chocolate(new MilkTea());
        System.out.println("巧克力奶茶:" + milkTea.price());
        
        Material milkTea_1 = new Coconut(new Pearl(new MilkTea()));
        System.out.println("珍珠椰果奶茶:" + milkTea_1.price());
    }
}
相關文章
相關標籤/搜索