跳转到内容

装饰器

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

待办事项
添加更多插图。


组合模式 计算机科学设计模式
装饰器
外观模式


您对本页有任何问题?
在这里提问


在本图书中创建一个新页面


华夏公益教科书