Head First设计模式_注释笔记

设计原则

  1. 把可能变化之处独立出来,以免影响固定代码。
  2. 针对接口编程,而不是针对实现编程
  3. 多用组合,少用继承
  4. 设计交互对象之间的松耦合
  5. 扩展-关闭原则:类应该对扩展开发,对修改关闭。
  6. 依赖抽象,不要依赖具体类。
  7. 最少知识原则:只和你的密友谈话。
  8. 好莱坞原则:高层组件对待低层组件的方式:别调用我们,我们会调用你。
    避免高层和低层出现明显的环装依赖
  9. 一个类应该只有一个引起变化的原因。高内聚,低耦合。(单一职责)

备注

1
2
3
4
5
6
7
8
9
10
11
12
//推荐
public int GetCount()
{
return target.GetCount(); //只认识target
}

//不推荐
public int GetCount()
{
var obj=target.GetObj(); //多认识(依赖)了一个对象
return obj.GetCount();
}

如果某对象是调用其他方法的返回结果,不要调用它的方法。意味着,不清楚他的方法细节。并不认识此对象,也就不依赖它。

针对接口(超类型)编程

针对实现:

1
2
Dog d=new Dog();
d.bark();

针对接口:

1
2
Animal a=new Dog();
a.makeSound();

运行时:

1
2
Animal a=getAnimal();
a.makeSound();

策略模式

定义

定义了算法族,分别封装起来,让它们之间可以互相替换。此模式让算法的变化独立于使用算法的客户。

类图

类图

观察者模式

定义

定义了对象间的一对多依赖(订阅),这样依赖,当一个对象改变时,它的所有依赖者都会受到通知并更新。Subject主题,Observer观察者。

类图

类图

代码示例

另可以用多播委托实现此过程。

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
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
public class DeleteAction : IDisposable
{
private readonly Action _onDispose;
public DeleteAction(Action onDispose)
{
_onDispose = onDispose;
}

public void Dispose()
{
_onDispose();
}
}

public class Msg
{
public string Name { get; set; }
}

public class Report : IObservable<Msg>
{
private List<IObserver<Msg>> os = new List<IObserver<Msg>>();

public void Notify(string msg)
{
os.ForEach(o =>
{
o.OnNext(new Msg { Name = msg });
o.OnCompleted();
});
}

public IDisposable Subscribe(IObserver<Msg> observer)
{
os.Add(observer);
return new DeleteAction(() => { os.Remove(observer); });
}

public void Err()
{
os.ForEach(o =>
{
o.OnError(new Exception("自定义错误!"));
});
}
}

public class Screen : IObserver<Msg>
{
public int Id { get; set; }

public Screen(int id)
{
Id = id;
}

public void OnNext(Msg value)
{
Console.WriteLine("接收Id:" + Id + ",信息为:" + value.Name);
}

public void OnError(Exception error)
{
Console.WriteLine("接收Id:" + Id + ",错误!信息:" + error.Message);
}

public void OnCompleted()
{
Console.WriteLine("接收Id:" + Id + ",完成!");
}
}

class Program
{
static void Main(string[] args)
{
Report re = new Report();
Screen s1 = new Screen(1);
Screen s2 = new Screen(2);
var o1 = re.Subscribe(s1);
var o2 = re.Subscribe(s2);
re.Notify("哎呀");
o1.Dispose();
re.Notify("少人");
}
}

装饰者模式

定义

动态地将责任附加到对象上。若要扩展功能,装饰者提供了比继承更有弹性的替代方案。

类图

类图

代码示例

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
63
64
65
public abstract class Phone
{
public abstract void Ring();
public abstract decimal GetPrice();
}

public class Apple : Phone //被装饰者
{
public override void Ring()
{
Console.WriteLine("这是苹果手机...");
}

public override decimal GetPrice()
{
return 4500;
}
}

public abstract class Decorator : Phone //装饰者
{
protected Phone p; //被装饰者引用
protected Decorator(Phone p)
{
this.p = p;
}
}

public class Sticker : Decorator
{
public Sticker(Phone p): base(p)
{
}

public override void Ring()
{
p.Ring(); //被装饰者行为
AddSticker(); //新增行为/责任
}

public override decimal GetPrice()
{
return p.GetPrice() + 1.5m;
}

public void AddSticker()
{
Console.WriteLine("加了贴膜!");
}
}

class Program
{
static void Main(string[] args)
{
Phone m = new Apple();
m = new Sticker(m);
m = new Sticker(m); //贴了2层
m = new Accessories(m);

m.Ring();
Console.WriteLine("当前价格为:" + m.GetPrice());
Console.ReadKey();
}
}

角色

抽象构件(Phone)角色:给出一个抽象接口,以规范准备接受附加责任的对象。

具体构件(AppPhone)角色:定义一个将要接收附加责任的类。

装饰(Dicorator)角色:持有一个构件(Component)对象的实例,并定义一个与抽象构件接口一致的接口。

具体装饰(Sticker和Accessories)角色:负责给构件对象 ”贴上“附加的责任。

理解

优点:

装饰者模式和继承的目的都是扩展对象的功能,但装饰者模式比继承更灵活通过使用不同的具体装饰类以及这些类的排列组合,设计师可以创造出很多不同行为的组合。装饰者模式有很好地可扩展性。

缺点:
装饰者模式会导致设计中出现许多小对象,如果过度使用,会让程序变的更复杂。并且更多的对象会是的差错变得困难,特别是这些对象看上去都很像。

适配器模式

定义

将一个类的接口,转换成客户(使用者)期望的另一个接口。适配器让原本不兼容的类可以合作无间。

类图

类图

代码示例

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
public interface IDuck    
{
void Quack();
}

public interface ITurkey
{
void SpecialQuack();
}

public class Duck : IDuck //鸭子类
{
public void Quack()
{
Console.WriteLine("鸭子叫!");
}
}

public class Turkey : ITurkey //火鸡类
{
public void SpecialQuack()
{
Console.WriteLine("火鸡叫!");
}
}

public class Adapter : IDuck //适配器,把火鸡转换成鸭子
{
private ITurkey t; //持有(包装)的火鸡引用
public Adapter(ITurkey t)
{
this.t = t;
}
public void Quack()
{
t.SpecialQuack();
}
}

class Program
{
static void Main(string[] args)
{
Adapter duckAdapter = new Adapter(new Turkey()); //使用适配器切换了接口
ShootDuck(duckAdapter); //原调用代码,不用更改。
Console.ReadKey();
}
static void ShootDuck(IDuck d)
{
d.Quack(); //原调用代码,不用更改。
}
}

理解

系统A,原本某一块功能(如客户出入金)需要从一个提供商甲切换到提供商乙,不改变系统代码的情况下。可以创建适配器,封装乙的接口实现切换动作,让系统仍然像使用甲的接口那样,正常运作。过程不需修改代码,只需扩展适配器。处理遗留问题。

装饰者和适配器的异同

适用条件的差别:

装饰模式一般在下列情况使用:需要扩展一个类的功能或者给你个类增加附加责任;需要动态的给一个对象增加功能,这些功能可以再动态的撤销;需要增加有一些基本功能的排列组合而产生非常大量的功能,从而使得继承关系变得不现实。

适配器模式一般使用的情况包括:系统需要使用现有的类,但此类已经不符合系统的需要;

想要建立一个可以重复使用的类,用于与一些彼此之间没有太大关联的一些类,包括一些可能在将来引进的的类一起工作。适配器模式在系统升级的时候使用的频率很高,对旧系统的一些功能方法在新系统中引用。

单例模式

定义

确保一个类只有一个实例,并提供一个全局访问点。

代码示例

线程安全

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public class Singleton
{
private Singleton() { }
private static Singleton singleton;
public static Singleton GetInstance()
{
if (singleton == null)
{
lock (typeof(Singleton))
{
if (singleton == null)
{
singleton = new Singleton();
}
}
}
return singleton;
}
}

命令模式

定义

将“请求”封装成对象,以便使用不同的请求、队列或日志来参数化其他对象。命令模式也支持可撤销的操作。

类图

类图

代码示例

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
public class Receiver
{
public void Action()
{
Console.WriteLine("Called Receiver.Action()");
}
}

public abstract class Command
{
protected Receiver receiver;

public Command(Receiver receiver)
{
this.receiver = receiver;
}

public abstract void Execute();
}

public class ConcreteCommand : Command
{
public ConcreteCommand(Receiver receiver): base(receiver)
{
}

public override void Execute()
{
receiver.Action();
}
}

public class Invoker
{
private Command _command;

public void SetCommand(Command command)
{
this._command = command;
}

public void ExecuteCommand()
{
_command.Execute();
}
}

class Program
{
static void Main(string[] args)
{
Receiver receiver = new Receiver();
Command command = new ConcreteCommand(receiver);
Invoker invoker = new Invoker();
invoker.SetCommand(command);
invoker.ExecuteCommand();
}
}

理解

将请求者和执行者(接受者)解耦:

如果执行者种类繁多,且不属于同一个体系,也没有统一执行接口。请求者请求命令,需要知道所有执行者的外露接口,耦合很高。

命令模式,加入中间层:调用者,让请求者只认识调用者,向调用者发出指定执行者且接口固定的命令对象,调用者只执行指定命令对象的固定接口,命令对象包含执行者的引用和一组方法,知道如何完成操作。这种封装命令对象的模式,为命令模式。如待完成列表,可以在任何时间被执行。

外观模式

定义

提供了一个统一的接口,用来访问子系统中的一群接口。外观定义了一个高层接口,让子系统更容易适用。

类图

类图

代理模式

定义

为另一个对象提供一个替身或占位符以控制对这个对象的访问。

类图

类图

类图

代理分类

  • 远程代理:为一个位于不同的地址空间的对象提供一个局域代表对象。这个不同的地址空间可以是在本机器中,也可是在另一台机器中。这样可以隐藏一个对象在不同地址空间的事实。
    例如:WebService,WCF
  • 虚拟代理: 根据需要创建一个资源消耗较大的对象,通过它来存放实例化需要长时间的真实对象,使得此对象只在需要时才会被真正创建
  • 保护代理:用来控制真实对象的访问时的权限。如果需要,可以给不同的用户提供不同级别的使用权限
  • 智能代理:指当调用真实对象时,代理处理另外一些事。提供一些额外的操作,比如将对此对象调用的次数记录下来等
  • 同步(Synchronization)代理:多线程情况下,为主题提供安全的访问
  • 复杂隐藏(Complexity Hiding)代理:隐藏一个类的复杂集合的复杂度,有时候称为外观代理(Facade Proxy)。此代理控制访问,外观模式只提供另一组接口
  • 写入时复制(Copy-on-Write)代理:虚拟代理的变种。把复制(克隆)延迟到只有在客户端需要时,才真正采取行动
  • 缓存(Cache)代理:为开销大的运算结果提供临时的存储空间,以便多个客户端可以共享这些结果,以减少计算或网络延迟
  • 防火墙(Firewall)代理:控制网络资源的访问,不让恶意用户接近

装饰者,外观,代理,适配器四种模式的比较

类图

工厂方法模式

定义

定义了一个创建对象的接口,但由子类决定要实例化的类是哪一个。工厂方法让类把实例化推迟到子类。

类图

类图

抽象工厂模式

定义

提供一个接口,用于创建相关或依赖对象的家族,而不需要明确指明具体类。

类图

类图

模板方法模式

定义

在一个方法中定义一个算法的骨架,而将一些步骤延迟到子类中。模板方法使得子类可以在不改变算法结构的情况下,重新定义算法中的某些步骤。

类图

类图

代码示例

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
public abstract class Beverage
{
public void Prepare()
{
BoilWater();
Brew();
PourInCup();
//钩子,可由子类视情况(是否覆盖),反控制基类中的算法(顺序或步骤)
if (IsCondiments())
{
AddCondiments();
}
}

protected abstract void AddCondiments(); //由子类实现部分算法
protected abstract void Brew(); //可有子类控制,推迟到子类中实现

protected virtual bool IsCondiments()
{
return false; //钩子
}

private void PourInCup()
{
Console.WriteLine("倒入杯子"); //基类默认实现部分
}

private void BoilWater()
{
Console.WriteLine("烧水");
}
}

public class Coffee : Beverage
{
protected override bool IsCondiments()
{
return GetResult(); //根据结果是否覆盖使用此钩子
}

protected override void AddCondiments()
{
Console.WriteLine("加糖,加奶");
}

protected override void Brew()
{
Console.WriteLine("磨碎咖啡豆,泡咖啡粉...");
}
}

class Program
{
static void Main(string[] args)
{
Beverage co = new Coffee();
co.Prepare();
}
}

模板方法模式的变种

不使用继承,而使用组合。

java中Arrays.sort(object[] arr)中的算法,进行两个对象之间的比较。

1
2
Comparable obj...     //接口
obj.compareTo(obj2)...

算法待实现部分,不再交由子类负责实现(数组不可继承)。而是传入一个实现了Comparable接口的元素组成的数组,由此数组的元素负责。

模板方法模式和工厂方法模式,区别

模板方法,指的是实现算法的方法,包含基类实现部分和待子类实现部分(抽象方法)。

工厂方法,指的是可由子类继承实现的抽象方法,不同子类决定不同的功能。会由基类调用。

迭代器模式

定义

提供一种方法顺序访问一个聚合对象中的各个元素,而又不暴露其内部的表示。

类图

类图

代码示例

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
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
public class Item
{
public string Name { get; set; }
public double Price { get; set; }

public override string ToString()
{
return "名称:" + Name + ",价格:" + rice;
}
}

public class MenuManager : IEnumerable //可被foreach迭代
{
private Item[] items;
private int Index { get; set; }
public MenuManager()
{
items = new Item[10];
AddItem("煎饼", 2);
AddItem("拉面", 7);
AddItem("快餐", 10);
}

public IEnumerator GetEnumerator()
{
return new MenuEnumrator(items); //继承实现,返回一个迭代器供foreach使用
}

public void AddItem(string name, double price)
{
Item i = new Item { Name = name, Price = price };
items[Index] = i;
Index++;
}

public void ChgItem(string name, double price, int destIndex)
{
Item i = new Item { Name = name, Price = price };
items[destIndex] = i;
}
}

public class MenuEnumrator : IEnumerator //迭代器接口
{
private List<Item> list;
private int index;
public MenuEnumrator(IEnumerable<Item> arr)
{
list = arr.ToList();
index = -1;
}

public bool MoveNext() //继承实现,先后移动
{
index++;
bool result = list.Count > index && list[index].Price < 3; //自定义条件
if (result)
Current = list[index];
return result;
}

public void Reset()
{
index = -1; //继承实现,重置索引
}

public object Current { get; private set; } //继承实现,当前项
}

class Program
{
static void Main(string[] args)
{
MenuManager dm = new MenuManager();
dm.AddItem("汽水", 1);
foreach (Item item in dm)
{
Console.WriteLine(item);
}
dm.ChgItem("干拌面", 9, 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
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
public class Graphics
{
protected string Name { get; set; }

protected Graphics(string name)
{
this.Name = name;
}

public virtual void Draw()
{
throw new NotSupportedException();
}

//默认抛出异常,避免叶对象或不合理的操作。
//简单图形(叶对象)Add或Remove方法没有任何意义
//如果客户端调用了将会抛出异常
public virtual void Add(Graphics g)
{
throw new NotSupportedException();
}

public virtual void Remove(Graphics g)
{
throw new NotSupportedException();
}
}

public class Line : Graphics
{
public Line(string name) : base(name)
{
}

public override void Draw()
{
Console.WriteLine("画 " + Name);
}
}

public class Circle : Graphics
{
public Circle(string name) : base(name)
{
}

public override void Draw()
{
Console.WriteLine("画 " + Name);
}
}

public class ComplexGraphics : Graphics
{
public ComplexGraphics(string name) : base(name)
{
}

private List<Graphics> list = new List<Graphics>();

public override void Draw()
{
foreach (var item in list)
item.Draw();
}

public override void Add(Graphics g)
{
list.Add(g);
}

public override void Remove(Graphics g)
{
list.Remove(g);
}
}

class Program
{
static void Main(string[] args)
{
Graphics complexGraphics = new ComplexGraphics("一个复杂图形和两条线段组成的复杂图形");
complexGraphics.Add(new Line("线段A"));
Graphics l = new Line("线段B");
complexGraphics.Add(l);
Graphics CompositeCG = new ComplexGraphics("一个圆和一条线组成的复杂图形");
CompositeCG.Add(new Circle("圆"));
CompositeCG.Add(new Circle("线段C"));
complexGraphics.Add(CompositeCG);

// 显示复杂图形的画法
Console.WriteLine("复杂图形的绘制如下:");
complexGraphics.Draw();
Console.WriteLine("复杂图形绘制完成\n");

// 移除一个组件再显示复杂图形的画法
complexGraphics.Remove(l);
Console.WriteLine("移除线段C后,复杂图形的绘制如下:");
complexGraphics.Draw();
Console.WriteLine("复杂图形绘制完成");
}
}

安全式的组合模式

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
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
public abstract class Graphics
{
protected string Name { get; set; }
protected Graphics(string name)
{
this.Name = name;
}

public abstract void Draw();
// 移除了Add和Remove方法
// 把管理子对象的方法放到了ComplexGraphics类中进行管理
// 因为这些方法只在复杂图形中才有意义,且符合单一责任原则。
}

public class Line : Graphics
{
public Line(string name) : base(name)
{
}

public override void Draw()
{
Console.WriteLine("画 " + Name);
}
}

public class Circle : Graphics
{
public Circle(string name) : base(name)
{
}

public override void Draw()
{
Console.WriteLine("画 " + Name);
}
}

public class ComplexGraphics : Graphics
{
public ComplexGraphics(string name) : base(name)
{
}

private List<Graphics> list = new List<Graphics>();
public override void Draw()
{
foreach (var item in list)
item.Draw();
}

public void Add(Graphics g)
{
list.Add(g);
}

public void Remove(Graphics g)
{
list.Remove(g);
}
}

class Program
{
static void Main(string[] args)
{
ComplexGraphics complexGraphics = new ComplexGraphics("一个复杂图形和两条线段组成的复杂图形");
complexGraphics.Add(new Line("线段A"));
Line l = new Line("线段B");
complexGraphics.Add(l);
ComplexGraphics CompositeCG = new ComplexGraphics("一个圆和一条线组成的复杂图形");
CompositeCG.Add(new Circle("圆"));
CompositeCG.Add(new Circle("线段C"));
complexGraphics.Add(CompositeCG);

// 显示复杂图形的画法
Console.WriteLine("复杂图形的绘制如下:");
complexGraphics.Draw();
Console.WriteLine("复杂图形绘制完成");

// 移除一个组件再显示复杂图形的画法
complexGraphics.Remove(l);
Console.WriteLine("移除线段C后,复杂图形的绘制如下:");
complexGraphics.Draw();
Console.WriteLine("复杂图形绘制完成");
}
}

状态模式

定义

允许对象在内部状态改变时改变它的行为,对象看起来好像修改了它的类。

类图

类图

代码示例

Machine:

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
public class Machine
{
internal State SoldOutState { get; set; } //内部包装的状态
internal State NoCoinState { get; set; }
internal State HasCoinState { get; set; }
internal State SoldingState { get; set; }
public int Count { get; internal set; } //对外暴露的显示
public int CoinCount { get; internal set; }
internal State State { get; set; }

public Machine(int count)
{
SoldOutState = new SoldOutState(this);
NoCoinState = new NoCoinState(this);
HasCoinState = new HasCoinState(this);
SoldingState = new SoldingState(this);
Count = count;
CoinCount = 0;
State = count > 0 ? NoCoinState : SoldOutState;
}

public void Insert() { State.Insert(); }
public void Eject() { State.Eject(); }
public void Turn() //对外暴露的接口(按钮)
{
State.Turn(); //内部执行的动作,由状态类负责
if (CoinCount > 0)
State.Give();
}

internal void SetState(State state) { State = state; }
public void FillBall(int count)
{
Console.WriteLine("上货" + count + "个");
Count += count;
}

internal void ReleaseBall()
{
Console.WriteLine("发放商品");
if (Count != 0)
Count--;
}

public override string ToString()
{
return "\n============================\n自动售货机\n货物个数:" + Count + "\t当前状态:" + State + "\n============================\n";
}
}

状态类:

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
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
internal abstract class State
{
public abstract void Insert();
public abstract void Eject();
public abstract void Turn();
public abstract void Give();
protected virtual void Error()
{
Console.WriteLine("错误操作");
}
}

internal class NoCoinState : State
{
private Machine Mac { get; set; }
public NoCoinState(Machine mac)
{
Mac = mac;
}

public override void Insert()
{
Console.WriteLine("投入硬币");
Mac.CoinCount++;
Mac.SetState(Mac.HasCoinState);
}

public override void Eject()
{
Error();
}

public override void Turn()
{
Error();
}

public override void Give()
{
Error();
}

public override string ToString()
{
return "等待投入硬币...";
}
}

internal class HasCoinState : State
{
private Machine Mac { get; set; }
public HasCoinState(Machine mac)
{
Mac = mac;
}

public override void Insert()
{
Error();
}

public override void Eject()
{
Console.WriteLine("硬币归还");
Mac.CoinCount--;
Mac.SetState(Mac.NoCoinState);
}

public override void Turn()
{
Console.WriteLine("转动");
Mac.SetState(Mac.SoldingState);
}

public override void Give()
{
Error();
}

public override string ToString()
{
return "有硬币,可以转动...";
}
}

internal class SoldingState : State
{
private Machine Mac { get; set; }
public SoldingState(Machine mac)
{
Mac = mac;
}

public override void Insert()
{
Error();
}

public override void Eject()
{
Error();
}

public override void Turn()
{
Error();
}

public override void Give()
{
Mac.ReleaseBall();
if (Mac.Count > 0)
Mac.SetState(Mac.NoCoinState);
else
{
Console.WriteLine("已售罄");
Mac.SetState(Mac.SoldOutState);
}
}

public override string ToString()
{
return "正在出货...";
}
}

internal class SoldOutState : State
{
private Machine Mac { get; set; }
public SoldOutState(Machine mac)
{
Mac = mac;
}

public override void Insert()
{
Error();
}

public override void Eject()
{
Error();
}

public override void Turn()
{
Error();
}

public override void Give()
{
Error();
}

public override string ToString()
{
return "已售罄...";
}
}

测试代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
class Program
{
static void Main(string[] args)
{
Machine mac = new Machine(5);
Console.WriteLine(mac);
mac.Eject();
mac.Turn();
mac.FillBall(1);
mac.Insert();
Console.WriteLine(mac);
mac.Eject();
mac.Insert();
mac.Insert();
mac.Turn();
mac.Turn();

Console.ReadKey();
}
}

模式配对

类图

模式分类

类图

欢迎打赏