设计模式-装饰器模式

Decorator

装饰模式通过将对象放入包含行为的特殊封装对象中来为原对象绑定新的行为

  • 对原有对象功能进行动态扩展,可通过组合不同装饰器实现不同功能
  • 系统的层次变得复杂

聚合而非继承

  • 继承是静态的,无法在执行时更改已有对象的行为,只能使用由不同子类创建的对象
  • 大部分编程语言不允许一个类同时继承多个类的行为,多个类扩展同一行为会创建大量子类

CPP

基本结构

Member FullName Description
抽象组件 Component 被装饰类接口
具体组件 Concrete Component 被装饰类具体代码实现
抽象装饰器 Decorator 装饰器类接口
具体装饰器 Concrete Decorator 装饰器具体实现,添加组件扩展功能

UML结构图

实现步骤

  1. 定义抽象组件,例如此处为饮料
1
2
3
4
5
6
class Beverage {
public:
virtual ~Beverage() = default;
virtual std::string getName() const = 0;
virtual double getPrice() const = 0;
};
  1. 定义具体组件,包括水和牛奶
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
class Water : public Beverage {
public:
std::string getName() const override {
return "Water";
}

double getPrice() const override {
return 0.0;
}
};

class Milk : public Beverage {
public:
std::string getName() const override {
return "Milk";
}

double getPrice() const override {
return 5.0;
}
};
  1. 定义抽象装饰器,调料
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
class Decorator : public Beverage {
protected:
Beverage* m_component;

public:
Decorator(Beverage* component) : m_component(component) {}

virtual ~Decorator() {
delete m_component;
}

std::string getName() const override {
return m_component->getName();
}

double getPrice() const override {
return m_component->getPrice();
}
};
  1. 定义具体装饰器,包括糖和咖啡
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
class SugarDecorator : public Decorator {
public:
SugarDecorator(Beverage* component) : Decorator(component) {}

std::string getName() const override {
return Decorator::getName() + " + Sugar";
}

double getPrice() const override {
return Decorator::getPrice() + 3.0;
}
};

class CoffeeDecorator : public Decorator {
public:
CoffeeDecorator(Beverage* component) : Decorator(component) {}

std::string getName() const override {
return Decorator::getName() + " + Coffee";
}

double getPrice() const override {
return Decorator::getPrice() + 5.0;
}
};
  1. 装饰过程
  • 不同子类采用同一装饰器:水和牛奶加糖
  • 一个子类叠加多种装饰器:水中加糖和咖啡
1
2
3
4
5
6
7
8
9
10
11
Beverage* water = new Water();
Beverage* milk = new Milk();

Beverage* sugaredWater = new SugarDecorator(water);
Beverage* sugaredMilk = new SugarDecorator(milk);

Beverage* coffeeSugaredWater = new CoffeeDecorator(sugaredWater);

std::cout << sugaredWater->getName() << " 的价格是 " << sugaredWater->getPrice() << std::endl;
std::cout << sugaredMilk->getName() << " 的价格是 " << sugaredMilk->getPrice() << std::endl;
std::cout << coffeeSugaredWater->getName() << " 的价格是 " << coffeeSugaredWater->getPrice() << std::endl;

Fortran

  1. 定义抽象组件
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
module Abstract_Component_Module
implicit none
private

type, public, abstract :: BeverageType
contains
procedure(getName), deferred :: getName
procedure(getPrice), deferred :: getPrice
end type BeverageType

abstract interface
pure function getName(this) result(name)
import :: BeverageType
class(BeverageType), intent(in) :: this
character(len=256) :: name
end function getName

pure function getPrice(this) result(price)
import :: BeverageType
class(BeverageType), intent(in) :: this
real :: price
end function getPrice
end interface
end module Abstract_Component_Module
  1. 定义具体组件
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
module Concrete_Component_Module
use Abstract_Component_Module, only : BeverageType
implicit none
private

type, public, extends(BeverageType) :: WaterType
contains
procedure :: getName => waterGetName
procedure :: getPrice => waterGetPrice
end type WaterType

type, public, extends(BeverageType) :: MilkType
contains
procedure :: getName => milkGetName
procedure :: getPrice => milkGetPrice
end type MilkType

contains

pure function waterGetName(this) result(name)
class(WaterType), intent(in) :: this
character(len=256) :: name
name = "Water"
end function waterGetName

pure function waterGetPrice(this) result(price)
class(WaterType), intent(in) :: this
real :: price
price = 0.0
end function waterGetPrice

pure function milkGetName(this) result(name)
class(MilkType), intent(in) :: this
character(len=256) :: name
name = "Milk"
end function milkGetName

pure function milkGetPrice(this) result(price)
class(MilkType), intent(in) :: this
real :: price
price = 5.0
end function milkGetPrice
end module Concrete_Component_Module
  1. 定义抽象装饰器
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
module Abstract_Decorator_Module
use Abstract_Component_Module, only : BeverageType
implicit none
private

type, public, abstract, extends(BeverageType) :: DecoratorType
class(BeverageType), pointer :: component => null()
contains
procedure :: getName => decoratorGetName
procedure :: getPrice => decoratorGetPrice
end type DecoratorType

contains

pure function decoratorGetName(this) result(name)
class(DecoratorType), intent(in) :: this
character(len=256) :: name
name = this%component%getName()
end function decoratorGetName

pure function decoratorGetPrice(this) result(price)
class(DecoratorType), intent(in) :: this
real :: price
price = this%component%getPrice()
end function decoratorGetPrice
end module Abstract_Decorator_Module
  1. 定义具体装饰器
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
module Concrete_Decorator_Module
use Abstract_Decorator_Module, only : DecoratorType
implicit none
private

type, public, extends(DecoratorType) :: SugarDecorator
contains
procedure :: getName => sugarGetName
procedure :: getPrice => sugarGetPrice
end type SugarDecorator

type, public, extends(DecoratorType) :: CoffeeDecorator
contains
procedure :: getName => coffeeGetName
procedure :: getPrice => coffeeGetPrice
end type CoffeeDecorator

contains

pure function sugarGetName(this) result(name)
class(SugarDecorator), intent(in) :: this
character(len=256) :: name
name = trim(this%component%getName()) // " + Sugar"
end function sugarGetName

pure function sugarGetPrice(this) result(price)
class(SugarDecorator), intent(in) :: this
real :: price
price = this%component%getPrice() + 3.0
end function sugarGetPrice

pure function coffeeGetName(this) result(name)
class(CoffeeDecorator), intent(in) :: this
character(len=256) :: name
name = trim(this%component%getName()) // " + Coffee"
end function coffeeGetName

pure function coffeeGetPrice(this) result(price)
class(CoffeeDecorator), intent(in) :: this
real :: price
price = this%component%getPrice() + 5.0
end function coffeeGetPrice
end module Concrete_Decorator_Module
  1. 创建对象
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
program main
use Abstract_Component_Module, only : BeverageType
use Concrete_Component_Module, only : WaterType, MilkType
use Abstract_Decorator_Module, only : DecoratorType
use Concrete_Decorator_Module, only : SugarDecorator, CoffeeDecorator
implicit none

class(BeverageType), pointer :: water, milk
class(DecoratorType), pointer :: sugaredWater, sugaredMilk, coffeeSugaredWater

allocate(WaterType :: water)
allocate(MilkType :: milk)

allocate(SugarDecorator :: sugaredWater)
sugaredWater%component => water

allocate(SugarDecorator :: sugaredMilk)
sugaredMilk%component => milk

allocate(CoffeeDecorator :: coffeeSugaredWater)
coffeeSugaredWater%component => sugaredWater

write(*, '(A, F5.1)') trim(sugaredWater%getName()), sugaredWater%getPrice()
write(*, '(A, F5.1)') trim(sugaredMilk%getName()), sugaredMilk%getPrice()
write(*, '(A, F5.1)') trim(coffeeSugaredWater%getName()), coffeeSugaredWater%getPrice()

deallocate(coffeeSugaredWater)
deallocate(sugaredMilk, sugaredWater)
deallocate(milk, water)
end program main

Reference

refactoringguru | 装饰器模式
Coder-ZZ | C++设计模式——Decorator装饰器模式

0%