装饰器
外观
目录
装饰器模式有助于为对象添加行为或责任。这也称为“包装器”。
示例
成本
这种模式可能非常昂贵。您应该只在确实需要时使用它。您应该为同一个类拥有许多不同的行为和责任。
创建
这种模式创建起来很昂贵。
维护
这种模式维护起来可能很昂贵。如果类的表示经常改变,您将需要进行大量重构。
删除
这种模式也很难删除。
建议
- 在装饰器类的名称中加上“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 继承来实现。
外部链接