【装饰模式】

描述:动态地给一个对象添加一些额外的职责。

有些时候我们需要给某个对象增加一些新的特性,使用继承机制是一种有效的方法,但是不够灵活。因为如果我们要使用继承扩展一个类,就必须要在编译的时候定义这个扩展的类,这是所谓的静态,也是强类型语言的特点。这时候可以使用装饰模式。

例子:

Weapon类

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
abstract class Weapon
{
private int attack;
public int Attack
{
get { return attack; }
set { attack = value; }
}
private int speed;
public int Speed
{
get { return speed; }
set { speed = value; }
}
private string name;
public string Name
{
get { return name; }
set { name = value; }
}
public abstract void ShowInfo();
}

Sword类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class Sword:Weapon
{
public Sword()
{
this.Attack = 100;
this.Speed = 50;
this.Name = "Sword";
}
public override void ShowInfo()
{
Console.WriteLine(string.Format("attack:{0}", Attack));
Console.WriteLine(string.Format("speed:{0}", Speed));
Console.WriteLine(string.Format("name:{0}", Name));
}
}

然后需要几个装饰器,将装饰器和Sword组装起来,实现功能的扩展

装饰器基类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
abstract class Decorator:Weapon
{
private Weapon w;
public Decorator(Weapon w)
{
this.w = w;
}
public override void ShowInfo()
{
w.ShowInfo();
}
}

增加Range属性的装饰器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
class RangeDecorator:Decorator
{
private int range;
public int Range
{
get { return range; }
set { range = value; }
}
public RangeDecorator(Weapon w):base(w)
{
this.Range = (int)(w.Speed + 20);
}
public void ShowRange()
{
Console.WriteLine(string.Format("range:{0}", Range));
}
}

增加Skill的装饰器

1
2
3
4
5
6
7
8
9
10
11
class SkillDecorator : Decorator
{
public SkillDecorator(Weapon w):base(w)
{
}
public void ShowSkill()
{
Console.WriteLine("Double Hit!");
}
}

如果我们需要给Sword增加Range属性,则

1
2
3
Weapon w = new Sword();
RangeDecorator rd = new RangeDecorator(w);
rd.ShowRange();

当然还可以用多个装饰器共同装饰一个对象,这就是为什么装饰器基类Decorator要继承自Weapon的原因。

1
2
3
4
5
6
Weapon w = new Sword();
w.ShowInfo();
SkillDecorator sd = new SkillDecorator(w);
sd.ShowSkill();
RangeDecorator rd = new RangeDecorator(sd);
rd.ShowRange();

简单来说,装饰模式就是创建多个类型等同于某一对象虚基类的饰品,用这些饰品装扮这些对象以便扩展它们的功能。装饰模式灵活易用,却增加了复杂度,所以在使用中需要特别注意不要过度使用。

【桥接模式】

描述:将抽象化与实现化分离。解决类型在多个维度上变化的问题。

描述看起来挺抽象,首先来说抽象化与实现化分离。这一点我们在之前的几个设计模式中都有体会,把几个类型的公共部分抽象出来作为基类,然后扩展。多维度变化是说某一个行为事件的发展方向,举例来说:车在路上,这是两个维度,车和路;人开车在路上,这就是三个维度。桥接模式就是来解决多个维度变化问题的。

例子:

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
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
public abstract class AbstractRoad
{
protected AbstractCar car;
public AbstractCar Car
{
set
{
car = value;
}
}
public virtual void Run()
{
car.Run();
}
}
public class Street:AbstractRoad
{
public override void Run()
{
base.Run();
Console.Write("街道");
}
}
public class SpeedWay : AbstractRoad
{
public override void Run()
{
base.Run();
Console.Write("高速公路");
}
}
public abstract class AbstractCar
{
public abstract void Run();
}
public class Car :AbstractCar
{
public override void Run()
{
Console.Write("汽车在");
}
}
public class Bus : AbstractCar
{
public override void Run()
{
Console.Write("公交车在");
}
}
//调用
AbstractRoad ar = new SpeedWay();
ar.Car = new Bus();
ar.Run();

可以看到桥接模式的作用就是把不同维度的事物以组合或聚合方式联系起来而不是通过继承,从而满足高内聚低耦合的特性。

【策略模式】

描述:定义了一系列的算法,并将每一个算法封装起来,而且使他们还可以互相替换。策略模式让算法独立于使用它的客户而独立变化。

例子:

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
abstract class Strategy
{
abstract public void Called();
}
class StrategyA : Strategy
{
public override void Called()
{
Console.Write("StrategyA Called");
}
}
class StrategyB : Strategy
{
public override void Called()
{
Console.Write("StrategyB Called");
}
}
class User
{
private Strategy s;
public void SetStrategy(Strategy s)
{
this.s = s;
}
public void UseStrategy(Strategy s)
{
if (s != null)
s.Called();
}
}
//调用
User user = new User();
StrategyA sa = new StrategyA();
user.SetStrategy(sa);
sa.Called();

简单来说策略模式的作用是定义了一个算法或行为族,把公共的代码移到父类里面,封装不同的算法。