裝飾器
外觀
目錄
裝飾器模式有助於為物件新增行為或責任。這也稱為“包裝器”。
示例
成本
這種模式可能非常昂貴。您應該只在確實需要時使用它。您應該為同一個類擁有許多不同的行為和責任。
建立
這種模式建立起來很昂貴。
維護
這種模式維護起來可能很昂貴。如果類的表示經常改變,您將需要進行大量重構。
刪除
這種模式也很難刪除。
建議
- 在裝飾器類的名稱中加上“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 繼承來實現。
外部連結
