跳轉到內容

裝飾器

25% developed
來自華夏公益教科書,開放的書籍,開放的世界

組合模式 計算機科學設計模式
裝飾器
外觀模式

裝飾器模式有助於為物件新增行為或責任。這也稱為“包裝器”。

示例

Clipboard

待辦事項
查詢示例。


成本

這種模式可能非常昂貴。您應該只在確實需要時使用它。您應該為同一個類擁有許多不同的行為和責任。

建立

這種模式建立起來很昂貴。

維護

這種模式維護起來可能很昂貴。如果類的表示經常改變,您將需要進行大量重構。

刪除

這種模式也很難刪除。

建議

  • 在裝飾器類的名稱中加上“decorator”一詞,以向其他開發人員表明該模式的使用。

實現

C# 實現

此示例說明了 bool 型別的簡單擴充套件方法。

using System;

// Extension methods must be parts of static classes.
static class BooleanExtensionMethodSample
{
    public static void Main()
    {
        bool yes = true;
        bool no = false;
        // Toggle the booleans! yes should return false and no should return true.
        Console.WriteLine(yes.Toggle());
        Console.WriteLine(no.Toggle());
    }
    // The extension method that adds Toggle to bool.
    public static bool Toggle(this bool target)
    {
        // Return the opposite of the target.
        return !target;
    }
}
C++ 實現

咖啡製作場景

# include <iostream>
# include <string>
// The abstract coffee class
class Coffee
{
public:
    virtual double getCost() = 0;
    virtual std::string getIngredient() = 0;
    virtual ~Coffee() {}
};
// Plain coffee without ingredient
class SimpleCoffee:public Coffee
{
private:
    double cost;
    std::string ingredient;
public:
    SimpleCoffee()
    {
        cost = 1;
        ingredient = std::string("Coffee");
    }
    double getCost()
    {
        return cost;
    }
    std::string getIngredient()
    {
        return ingredient;
    }
};
// Abstract decorator class
class CoffeeDecorator:public Coffee
{
protected:
    Coffee & decoratedCoffee;
public:
    CoffeeDecorator(Coffee & decoratedCoffee):decoratedCoffee(decoratedCoffee){}
    ~CoffeeDecorator()  {
        delete &decoratedCoffee;
    }
};
// Milk Decorator
class Milk:public CoffeeDecorator
{
private:
    double cost;
public:
    Milk(Coffee & decoratedCoffee):CoffeeDecorator(decoratedCoffee)
    {
        cost = 0.5;
    }
    double getCost()
    {
        return cost + decoratedCoffee.getCost();
    }
    std::string getIngredient()
    {
        return "Milk "+decoratedCoffee.getIngredient();
    }
};
// Whip decorator
class Whip:public CoffeeDecorator
{
private:
    double cost;
public:
    Whip(Coffee & decoratedCoffee):CoffeeDecorator(decoratedCoffee)
    {
        cost = 0.7;
    }
    double getCost()
    {
        return cost + decoratedCoffee.getCost();
    }
    std::string getIngredient()
    {
        return "Whip "+decoratedCoffee.getIngredient();
    }
};
// Sprinkles decorator
class Sprinkles:public CoffeeDecorator
{
private:
    double cost;
public:
    Sprinkles(Coffee & decoratedCoffee):CoffeeDecorator(decoratedCoffee)
    {
        cost = 0.6;
    }
    double getCost()
    {
        return cost + decoratedCoffee.getCost();
    }
    std::string getIngredient()
    {
        return "Sprinkles "+decoratedCoffee.getIngredient();
    }
};
// Here's a test
int main()
{
    Coffee* sample;
    sample = new SimpleCoffee();
    sample = new Milk(*sample);
    sample = new Whip(*sample);
    std::cout << sample->getIngredient() << std::endl;
    std::cout << "Cost: " << sample->getCost() << std::endl;
    delete sample;
}

該程式的輸出如下所示

攪拌牛奶咖啡
成本:2.2

JavaScript 實現
// Class to be decorated
function Coffee() {
    this.cost = function() {
return 1;
    };
}
// Decorator A
function Milk(coffee) {
    this.cost = function() {
return coffee.cost() + 0.5;
    };
}
// Decorator B
function Whip(coffee) {
    this.cost = function() {
return coffee.cost() + 0.7;
    };
}
// Decorator C
function Sprinkles(coffee) {
    this.cost = function() {
return coffee.cost() + 0.2;
    };
}
// Here's one way of using it
var coffee = new Milk(new Whip(new Sprinkles(new Coffee())));
alert( coffee.cost() );
// Here's another
var coffee = new Coffee();
coffee = new Sprinkles(coffee);
coffee = new Whip(coffee);
coffee = new Milk(coffee);
alert(coffee.cost());
Kotlin 實現
fun printInfo(c: Coffee) {
    println("Cost: " + c.cost + "; Ingredients: " + c.ingredients)
}

fun main(args: Array<String>) {
    var c: Coffee = SimpleCoffee()
    printInfo(c)

    c = WithMilk(c)
    printInfo(c)

    c = WithSprinkles(c)
    printInfo(c)
}

// The interface Coffee defines the functionality of Coffee implemented by decorator
interface Coffee {
    val cost: Double // Returns the cost of the coffee
    val ingredients: String // Returns the ingredients of the coffee
}

// Extension of a simple coffee without any extra ingredients
class SimpleCoffee : Coffee {
    override val cost: Double
        get() = 1.0

    override val ingredients: String
        get() = "Coffee"
}

// Abstract decorator class - note that it implements Coffee interface
abstract class CoffeeDecorator(private val decoratedCoffee: Coffee) : Coffee {

    override// Implementing methods of the interface
    val cost: Double
        get() = decoratedCoffee.cost

    override val ingredients: String
        get() = decoratedCoffee.ingredients
}

// Decorator WithMilk mixes milk into coffee.
// Note it extends CoffeeDecorator.
class WithMilk(c: Coffee) : CoffeeDecorator(c) {

    override// Overriding methods defined in the abstract superclass
    val cost: Double
        get() = super.cost + 0.5

    override val ingredients: String
        get() = super.ingredients + ", Milk"
}

// Decorator WithSprinkles mixes sprinkles onto coffee.
// Note it extends CoffeeDecorator.
class WithSprinkles(c: Coffee) : CoffeeDecorator(c) {

    override val cost: Double
        get() = super.cost + 0.2

    override val ingredients: String
        get() = super.ingredients + ", Sprinkles"
}

該程式的輸出如下所示

成本:1.0;配料:咖啡
成本:1.5;配料:咖啡,牛奶
成本:1.7;配料:咖啡,牛奶,糖粉

Java 實現

第一個示例(視窗/滾動場景)

以下 Java 示例說明了使用視窗/滾動場景的裝飾器。

// the Window abstract class
public abstract class Window {
    public abstract void draw(); // draws the Window
    public abstract String getDescription(); // returns a description of the Window
}
// extension of a simple Window without any scrollbars
class SimpleWindow extends Window {
    public void draw() {
        // draw window
    }
    public String getDescription() {
        return "simple window";
    }
}

以下類包含所有裝飾器視窗類,包括裝飾器類本身。

// abstract decorator class - note that it extends Window
abstract class WindowDecorator extends Window {
    protected Window decoratedWindow; // the Window being decorated
    public WindowDecorator (Window decoratedWindow) {
        this.decoratedWindow = decoratedWindow;
    }
    public void draw() {
        decoratedWindow.draw(); //delegation
    }
    public String getDescription() {
        return decoratedWindow.getDescription(); //delegation
    }
}
// the first concrete decorator which adds vertical scrollbar functionality
class VerticalScrollBarDecorator extends WindowDecorator {
    public VerticalScrollBarDecorator (Window decoratedWindow) {
        super(decoratedWindow);
    }
    @Override
    public void draw() {
        super.draw();
        drawVerticalScrollBar();
    }
    private void drawVerticalScrollBar() {
        // draw the vertical scrollbar
    }
    @Override
    public String getDescription() {
        return super.getDescription() + ", including vertical scrollbars";
    }
}
// the second concrete decorator which adds horizontal scrollbar functionality
class HorizontalScrollBarDecorator extends WindowDecorator {
    public HorizontalScrollBarDecorator (Window decoratedWindow) {
        super(decoratedWindow);
    }
    @Override
    public void draw() {
        super.draw();
        drawHorizontalScrollBar();
    }
    private void drawHorizontalScrollBar() {
        // draw the horizontal scrollbar
    }
    @Override
    public String getDescription() {
        return super.getDescription() + ", including horizontal scrollbars";
    }
}

這是一個建立測試程式視窗一個完全裝飾的例項(即帶有垂直和水平捲軸),並列印其描述

public class DecoratedWindowTest {
    public static void main(String[] args) {
        // create a decorated Window with horizontal and vertical scrollbars
        Window decoratedWindow = new HorizontalScrollBarDecorator (
                new VerticalScrollBarDecorator(new SimpleWindow()));
        // print the Window's description
        System.out.println(decoratedWindow.getDescription());
    }
}

該程式的輸出為“簡單視窗,包括垂直捲軸,包括水平捲軸”。注意兩個裝飾器的getDescription方法首先檢索裝飾的視窗的描述,並用字尾裝飾它。

第二個示例(咖啡製作場景)

下一個 Java 示例說明了使用咖啡製作場景的裝飾器。在本示例中,該場景僅包含成本和配料。

// The abstract Coffee class defines the functionality of Coffee implemented by decorator
public abstract class Coffee {
    public abstract double getCost(); // returns the cost of the coffee
    public abstract String getIngredients(); // returns the ingredients of the coffee
}
// extension of a simple coffee without any extra ingredients
public class SimpleCoffee extends Coffee {
    public double getCost() {
        return 1;
    }
    public String getIngredients() {
        return "Coffee";
    }
}

以下類包含所有裝飾器咖啡類,包括裝飾器類本身。

// abstract decorator class - note that it extends Coffee abstract class
public abstract class CoffeeDecorator extends Coffee {
    protected final Coffee decoratedCoffee;
    protected String ingredientSeparator = ", ";
    public CoffeeDecorator(Coffee decoratedCoffee) {
        this.decoratedCoffee = decoratedCoffee;
    }
    public double getCost() { // implementing methods of the abstract class
        return decoratedCoffee.getCost();
    }
    public String getIngredients() {
        return decoratedCoffee.getIngredients();
    }
}
// Decorator Milk that mixes milk with coffee
// note it extends CoffeeDecorator
class Milk extends CoffeeDecorator {
    public Milk(Coffee decoratedCoffee) {
        super(decoratedCoffee);
    }
    public double getCost() { // overriding methods defined in the abstract superclass
        return super.getCost() + 0.5;
    }
    public String getIngredients() {
        return super.getIngredients() + ingredientSeparator + "Milk";
    }
}
// Decorator Whip that mixes whip with coffee
// note it extends CoffeeDecorator
class Whip extends CoffeeDecorator {
    public Whip(Coffee decoratedCoffee) {
        super(decoratedCoffee);
    }
    public double getCost() {
        return super.getCost() + 0.7;
    }
    public String getIngredients() {
        return super.getIngredients() + ingredientSeparator + "Whip";
    }
}
// Decorator Sprinkles that mixes sprinkles with coffee
// note it extends CoffeeDecorator
class Sprinkles extends CoffeeDecorator {
    public Sprinkles(Coffee decoratedCoffee) {
        super(decoratedCoffee);
    }
    public double getCost() {
        return super.getCost() + 0.2;
    }
    public String getIngredients() {
        return super.getIngredients() + ingredientSeparator + "Sprinkles";
    }
}

這是一個建立測試程式咖啡一個完全裝飾的例項(即帶有牛奶、攪拌、糖粉),並計算咖啡的成本並列印其配料

public class Main {
   
    public static final void main(String[] args) {
Coffee c = new SimpleCoffee();
System.out.println("Cost: " + c.getCost() + "; Ingredients: " + c.getIngredients());
c = new Milk(c);
System.out.println("Cost: " + c.getCost() + "; Ingredients: " + c.getIngredients());
c = new Sprinkles(c);
System.out.println("Cost: " + c.getCost() + "; Ingredients: " + c.getIngredients());
c = new Whip(c);
System.out.println("Cost: " + c.getCost() + "; Ingredients: " + c.getIngredients());
// Note that you can also stack more than one decorator of the same type
c = new Sprinkles(c);
System.out.println("Cost: " + c.getCost() + "; Ingredients: " + c.getIngredients());
    }
   
}

該程式的輸出如下所示

成本:1.0 配料:咖啡
成本:1.5 配料:咖啡,牛奶
成本:1.7 配料:咖啡,牛奶,糖粉
成本:2.4 配料:咖啡,牛奶,糖粉,攪拌

Python 實現

視窗系統

# the Window base class
class Window(object):
    def draw(self, device):
        device.append('flat window')
    def info(self):
        pass
# The decorator pattern approch
class WindowDecorator:
    def __init__(self, w):
        self.window = w
    def draw(self, device):
        self.window.draw(device)
    def info(self):
        self.window.info()
class BorderDecorator(WindowDecorator):
    def draw(self, device):
        self.window.draw(device)
        device.append('borders')
class ScrollDecorator(WindowDecorator):
    def draw(self, device):
        self.window.draw(device)
        device.append('scroll bars')
def test_deco():
    # The way of using the decorator classes
    w = ScrollDecorator(BorderDecorator(Window()))
    dev = []
    w.draw(dev)
    print dev
test_deco()

子類方法和裝飾器模式的區別

# The subclass approch
class BorderedWindow(Window):
    def draw(self, device):
        super(BorderedWindow, self).draw(device)
        device.append('borders')
class ScrolledWindow(Window):
    def draw(self, device):
        super(ScrolledWindow, self).draw(device)
        device.append('scroll bars')
# combine the functionalities using multiple inheritance.
class MyWindow(ScrolledWindow, BorderedWindow, Window):
    pass
def test_muli():
    w = MyWindow()
    dev = []
    w.draw(dev)
    print dev
def test_muli2():
    # note that python can create a class on the fly.
    MyWindow = type('MyWindow', (ScrolledWindow, BorderedWindow, Window), {})
    w = MyWindow()
    dev = []
    w.draw(dev)
    print dev
test_muli()
test_muli2()
F# 實現

咖啡示例

type Coffee() = 
    abstract member Cost : double
    abstract member Ingredients: string list
    
    default this.Cost = 1.0
    default this.Ingredients = ["Coffee"]

type CoffeeDecorator(coffee: Coffee) = 
     inherit Coffee ()
     override this.Cost = coffee.Cost
     override this.Ingredients = coffee.Ingredients

type WithMilk(coffee: Coffee) = 
    inherit CoffeeDecorator(coffee)
    override this.Cost = base.Cost + 0.5
    override this.Ingredients = ["Milk"] |> List.append base.Ingredients

type WithSprinkles(coffee: Coffee) = 
    inherit CoffeeDecorator(coffee)
    override this.Cost = base.Cost + 0.2
    override this.Ingredients = ["Sprinkles"] |> List.append base.Ingredients

let print (coffee: Coffee) = 
    printfn "Cost: %.2f$; Ingredients: %A" coffee.Cost coffee.Ingredients       

let withAddins = Coffee() |> WithMilk |> WithSprinkles
print withAddins

動態語言

裝飾器模式也可以在動態語言中使用介面或傳統的 OOP 繼承來實現。


Clipboard

待辦事項
新增更多插圖。


組合模式 計算機科學設計模式
裝飾器
外觀模式


您對本頁有任何問題?
在這裡提問


在本圖書中建立一個新頁面


華夏公益教科書