Template Method,模板方法:定义一个操作中的算法的骨架,而将一些步骤延迟到子类中,TemplateMethod使得子类可以不改变一个算法的结构即可以重定义该算法的某些特定步骤。 应用场景:一个操作的步骤稳定,而具体细节的改变延迟的子类
http://www.cnblogs.com/zhili/p/TemplateMethodPattern.html
http://www.cnblogs.com/PatrickLiu/p/7837716.html
Template Method,模板方法:定义一个操作中的算法的骨架,而将一些步骤延迟到子类中,TemplateMethod使得子类可以不改变一个算法的结构即可以重定义该算法的某些特定步骤。 应用场景:一个操作的步骤稳定,而具体细节的改变延迟的子类
http://www.cnblogs.com/zhili/p/TemplateMethodPattern.html
http://www.cnblogs.com/PatrickLiu/p/7837716.html
State,状态模式:允许对象在其内部状态改变时改变他的行为。对象看起来似乎改变了他的类。 应用场景:一个对象的内部状态改变时,他的行为剧烈的变化。
http://www.cnblogs.com/zhili/p/StatePattern.html
http://www.cnblogs.com/PatrickLiu/p/8032683.html
在上一篇文章介绍到可以使用状态者模式和观察者模式来解决中介者模式存在的问题,在本文中将首先通过一个银行账户的例子来解释状态者模式,通过这个例子使大家可以对状态者模式有一个清楚的认识,接着,再使用状态者模式来解决上一篇文章中提出的问题。
每个对象都有其对应的状态,而每个状态又对应一些相应的行为,如果某个对象有多个状态时,那么就会对应很多的行为。那么对这些状态的判断和根据状态完成的行为,就会导致多重条件语句,并且如果添加一种新的状态时,需要更改之前现有的代码。这样的设计显然违背了开闭原则。状态模式正是用来解决这样的问题的。状态模式将每种状态对应的行为抽象出来成为单独新的对象,这样状态的变化不再依赖于对象内部的行为。
上面对状态模式做了一个简单的介绍,这里给出状态模式的定义。
状态模式——允许一个对象在其内部状态改变时自动改变其行为,对象看起来就像是改变了它的类。
既然状态者模式是对已有对象的状态进行抽象,则自然就有抽象状态者类和具体状态者类,而原来已有对象需要保存抽象状态者类的引用,通过调用抽象状态者的行为来改变已有对象的行为。经过上面的分析,状态者模式的结构图也就很容易理解了,具体结构图如下图示。
从上图可知,状态者模式涉及以下三个角色:
下面,就以银行账户的状态来实现下状态者模式。银行账户根据余额可分为RedState、SilverState和GoldState。这些状态分别代表透支账号,新开账户和标准账户。账号余额在【-100.0,0.0】范围表示处于RedState状态,账号余额在【0.0 , 1000.0】范围表示处于SilverState,账号在【1000.0, 100000.0】范围表示处于GoldState状态。下面以这样的一个场景实现下状态者模式,具体实现代码如下所示:
1 namespace StatePatternSample 2 {
3 public class Account 4 {
5 public State State {get;set;}
6 public string Owner { get; set; }
7 public Account(string owner) 8 {
9 this.Owner = owner; 10 this.State = new SilverState(0.0, this);
11 }
12
13 public double Balance { get {return State.Balance; }} // 余额 14 // 存钱
15 public void Deposit(double amount) 16 {
17 State.Deposit(amount);
18 Console.WriteLine(“存款金额为 {0:C}——“, amount);
19 Console.WriteLine(“账户余额为 =:{0:C}”, this.Balance);
20 Console.WriteLine(“账户状态为: {0}”, this.State.GetType().Name);
21 Console.WriteLine();
22 }
23
24 // 取钱
25 public void Withdraw(double amount) 26 {
27 State.Withdraw(amount);
28 Console.WriteLine(“取款金额为 {0:C}——“,amount);
29 Console.WriteLine(“账户余额为 =:{0:C}”, this.Balance);
30 Console.WriteLine(“账户状态为: {0}”, this.State.GetType().Name);
31 Console.WriteLine();
32 }
33
34 // 获得利息
35 public void PayInterest() 36 {
37 State.PayInterest();
38 Console.WriteLine(“Interest Paid — “);
39 Console.WriteLine(“账户余额为 =:{0:C}”, this.Balance);
40 Console.WriteLine(“账户状态为: {0}”, this.State.GetType().Name);
41 Console.WriteLine();
42 }
43 }
44
45 // 抽象状态类
46 public abstract class State 47 {
48 // Properties
49 public Account Account { get; set; }
50 public double Balance { get; set; } // 余额
51 public double Interest { get; set; } // 利率
52 public double LowerLimit { get; set; } // 下限
53 public double UpperLimit { get; set; } // 上限
54
55 public abstract void Deposit(double amount); // 存款
56 public abstract void Withdraw(double amount); // 取钱
57 public abstract void PayInterest(); // 获得的利息
58 }
59
60 // Red State意味着Account透支了
61 public class RedState : State 62 {
63 public RedState(State state) 64 {
65 // Initialize
66 this.Balance = state.Balance; 67 this.Account = state.Account; 68 Interest = 0.00;
69 LowerLimit = -100.00;
70 UpperLimit = 0.00;
71 }
72
73 // 存款
74 public override void Deposit(double amount) 75 {
76 Balance += amount; 77 StateChangeCheck();
78 }
79 // 取钱
80 public override void Withdraw(double amount) 81 {
82 Console.WriteLine(“没有钱可以取了!”);
83 }
84
85 public override void PayInterest() 86 {
87 // 没有利息
88 }
89
90 private void StateChangeCheck() 91 {
92 if (Balance > UpperLimit) 93 {
94 Account.State = new SilverState(this);
95 }
96 }
97 }
98
99 // Silver State意味着没有利息得
100 public class SilverState :State 101 { 102 public SilverState(State state) 103 : this(state.Balance, state.Account) 104 { 105 } 106
107 public SilverState(double balance, Account account) 108 { 109 this.Balance = balance; 110 this.Account = account; 111 Interest = 0.00; 112 LowerLimit = 0.00; 113 UpperLimit = 1000.00; 114 } 115
116 public override void Deposit(double amount) 117 { 118 Balance += amount; 119 StateChangeCheck(); 120 } 121 public override void Withdraw(double amount) 122 { 123 Balance -= amount; 124 StateChangeCheck(); 125 } 126
127 public override void PayInterest() 128 { 129 Balance += Interest * Balance; 130 StateChangeCheck(); 131 } 132
133 private void StateChangeCheck() 134 { 135 if (Balance < LowerLimit) 136 { 137 Account.State = new RedState(this); 138 } 139 else if (Balance > UpperLimit) 140 { 141 Account.State = new GoldState(this); 142 } 143 } 144 } 145
146 // Gold State意味着有利息状态
147 public class GoldState : State 148 { 149 public GoldState(State state) 150 { 151 this.Balance = state.Balance; 152 this.Account = state.Account; 153 Interest = 0.05; 154 LowerLimit = 1000.00; 155 UpperLimit = 1000000.00; 156 } 157 // 存钱
158 public override void Deposit(double amount) 159 { 160 Balance += amount; 161 StateChangeCheck(); 162 } 163 // 取钱
164 public override void Withdraw(double amount) 165 { 166 Balance -= amount; 167 StateChangeCheck(); 168 } 169 public override void PayInterest() 170 { 171 Balance += Interest * Balance; 172 StateChangeCheck(); 173 } 174
175 private void StateChangeCheck() 176 { 177 if (Balance < 0.0) 178 { 179 Account.State = new RedState(this); 180 } 181 else if (Balance < LowerLimit) 182 { 183 Account.State = new SilverState(this); 184 } 185 } 186 } 187
188 class App 189 { 190 static void Main(string[] args) 191 { 192 // 开一个新的账户
193 Account account = new Account(“Learning Hard”); 194
195 // 进行交易 196 // 存钱
197 account.Deposit(1000.0); 198 account.Deposit(200.0); 199 account.Deposit(600.0); 200
201 // 付利息
202 account.PayInterest(); 203
204 // 取钱
205 account.Withdraw(2000.00); 206 account.Withdraw(500.00); 207
208 // 等待用户输入
209 Console.ReadKey(); 210 } 211 } 212 }
上面代码的运行结果如下图所示:
从上图可以发现,进行存取款交易,会影响到Account内部的状态,由于状态的改变,从而影响到Account类行为的改变,而且这些操作都是发生在运行时的。
在上一篇博文中,我曾介绍到中介者模式存在的问题,详细的问题描述可以参考上一篇博文。下面利用观察者模式和状态者模式来完善中介者模式,具体的实现代码如下所示:
1 // 抽象牌友类
2 public abstract class AbstractCardPartner 3 {
4 public int MoneyCount { get; set; }
5
6 public AbstractCardPartner() 7 {
8 MoneyCount = 0;
9 }
10
11 public abstract void ChangeCount(int Count, AbstractMediator mediator); 12 }
13
14 // 牌友A类
15 public class ParterA : AbstractCardPartner 16 {
17 // 依赖与抽象中介者对象
18 public override void ChangeCount(int Count, AbstractMediator mediator) 19 {
20 mediator.ChangeCount(Count);
21 }
22 }
23
24 // 牌友B类
25 public class ParterB : AbstractCardPartner 26 {
27 // 依赖与抽象中介者对象
28 public override void ChangeCount(int Count, AbstractMediator mediator) 29 {
30 mediator.ChangeCount(Count);
31 }
32 }
33
34 // 抽象状态类
35 public abstract class State 36 {
37 protected AbstractMediator meditor; 38 public abstract void ChangeCount(int count); 39 }
40
41 // A赢状态类
42 public class AWinState : State 43 {
44 public AWinState(AbstractMediator concretemediator) 45 {
46 this.meditor = concretemediator; 47 }
48
49 public override void ChangeCount(int count) 50 {
51 foreach (AbstractCardPartner p in meditor.list) 52 {
53 ParterA a = p as ParterA; 54 //
55 if (a != null)
56 {
57 a.MoneyCount += count; 58 }
59 else
60 {
61 p.MoneyCount -= count; 62 }
63 }
64 }
65 }
66
67 // B赢状态类
68 public class BWinState : State 69 {
70 public BWinState(AbstractMediator concretemediator) 71 {
72 this.meditor = concretemediator; 73 }
74
75 public override void ChangeCount(int count) 76 {
77 foreach (AbstractCardPartner p in meditor.list) 78 {
79 ParterB b = p as ParterB; 80 // 如果集合对象中时B对象,则对B的钱添加
81 if (b != null)
82 {
83 b.MoneyCount += count; 84 }
85 else
86 {
87 p.MoneyCount -= count; 88 }
89 }
90 }
91 }
92
93 // 初始化状态类
94 public class InitState : State 95 {
96 public InitState() 97 {
98 Console.WriteLine(“游戏才刚刚开始,暂时还有玩家胜出”);
99 } 100
101 public override void ChangeCount(int count) 102 { 103 //
104 return; 105 } 106 } 107
108 // 抽象中介者类
109 public abstract class AbstractMediator 110 { 111 public List
113 public State State { get; set; } 114
115 public AbstractMediator(State state) 116 { 117 this.State = state; 118 } 119
120 public void Enter(AbstractCardPartner partner) 121 { 122 list.Add(partner); 123 } 124
125 public void Exit(AbstractCardPartner partner) 126 { 127 list.Remove(partner); 128 } 129
130 public void ChangeCount(int count) 131 { 132 State.ChangeCount(count); 133 } 134 } 135
136 // 具体中介者类
137 public class MediatorPater : AbstractMediator 138 { 139 public MediatorPater(State initState) 140 : base(initState) 141 { } 142 } 143
144 class Program 145 { 146 static void Main(string[] args) 147 { 148 AbstractCardPartner A = new ParterA(); 149 AbstractCardPartner B = new ParterB(); 150 // 初始钱
151 A.MoneyCount = 20; 152 B.MoneyCount = 20; 153
154 AbstractMediator mediator = new MediatorPater(new InitState()); 155
156 // A,B玩家进入平台进行游戏
157 mediator.Enter(A); 158 mediator.Enter(B); 159
160 // A赢了
161 mediator.State = new AWinState(mediator); 162 mediator.ChangeCount(5); 163 Console.WriteLine(“A 现在的钱是:{0}”, A.MoneyCount);// 应该是25
164 Console.WriteLine(“B 现在的钱是:{0}”, B.MoneyCount); // 应该是15 165
166 // B 赢了
167 mediator.State = new BWinState(mediator); 168 mediator.ChangeCount(10); 169 Console.WriteLine(“A 现在的钱是:{0}”, A.MoneyCount);// 应该是25
170 Console.WriteLine(“B 现在的钱是:{0}”, B.MoneyCount); // 应该是15
171 Console.Read(); 172 } 173 }
View Code
在以下情况下可以考虑使用状态者模式。
状态者模式的主要优点是:
状态者模式的主要缺点是:
状态者模式是对对象状态的抽象,从而把对象中对状态复杂的判断逻辑已到各个状态类里面,从而简化逻辑判断。在下一篇文章将分享我对策略模式的理解。
这个系列也是自己对设计模式的一些学习笔记,希望对一些初学设计模式的人有所帮助的,在上一个专题中介绍了单例模式,在这个专题中继续为大家介绍一个比较容易理解的模式——简单工厂模式。
说到简单工厂,自然的第一个疑问当然就是什么是简单工厂模式了? 在现实生活中工厂是负责生产产品的,同样在设计模式中,简单工厂模式我们也可以理解为负责生产对象的一个类, 我们平常编程中,当使用”new”关键字创建一个对象时,此时该类就依赖与这个对象,也就是他们之间的耦合度高,当需求变化时,我们就不得不去修改此类的源码,此时我们可以运用面向对象(OO)的很重要的原则去解决这一的问题,该原则就是——封装改变,既然要封装改变,自然也就要找到改变的代码,然后把改变的代码用类来封装,这样的一种思路也就是我们简单工厂模式的实现方式了。下面通过一个现实生活中的例子来引出简单工厂模式。
在外面打工的人,免不了要经常在外面吃饭,当然我们也可以自己在家做饭吃,但是自己做饭吃麻烦,因为又要自己买菜,然而,出去吃饭就完全没有这些麻烦的,我们只需要到餐馆点菜就可以了,买菜的事情就交给餐馆做就可以了,这里餐馆就充当简单工厂的角色,下面让我们看看现实生活中的例子用代码是怎样来表现的。
自己做饭的情况:
///
/// 自己做饭的情况 /// 没有简单工厂之前,客户想吃什么菜只能自己炒的 ///
public class Customer
{ ///
/// 烧菜方法 ///
///
///
public static Food Cook(string type)
{
Food food = null; // 客户A说:我想吃西红柿炒蛋怎么办? // 客户B说:那你就自己烧啊 // 客户A说: 好吧,那就自己做吧
if (type.Equals(“西红柿炒蛋”))
{
food = new TomatoScrambledEggs();
} // 我又想吃土豆肉丝, 这个还是得自己做 // 我觉得自己做好累哦,如果能有人帮我做就好了?
else if (type.Equals(“土豆肉丝”))
{
food = new ShreddedPorkWithPotatoes();
} return food;
} static void Main(string[] args)
{ // 做西红柿炒蛋
Food food1 = Cook(“西红柿炒蛋”);
food1.Print();
Food food2 \= Cook("土豆肉丝");
food2.Print();
Console.Read();
}
} /// <summary>
/// 菜抽象类 /// </summary>
public abstract class Food
{ // 输出点了什么菜
public abstract void Print();
} /// <summary>
/// 西红柿炒鸡蛋这道菜 /// </summary>
public class TomatoScrambledEggs : Food
{ public override void Print()
{
Console.WriteLine("一份西红柿炒蛋!");
}
} /// <summary>
/// 土豆肉丝这道菜 /// </summary>
public class ShreddedPorkWithPotatoes : Food
{ public override void Print()
{
Console.WriteLine("一份土豆肉丝");
}
}
自己做饭,如果我们想吃别的菜时,此时就需要去买这种菜和洗菜这些繁琐的操作,有了餐馆(也就是简单工厂)之后,我们就可以把这些操作交给餐馆去做,此时消费者(也就是我们)对菜(也就是具体对象)的依赖关系从直接变成的间接的,这样就是实现了面向对象的另一个原则——降低对象之间的耦合度,下面就具体看看有了餐馆之后的实现代码(即简单工厂的实现):
///
/// 顾客充当客户端,负责调用简单工厂来生产对象 /// 即客户点菜,厨师(相当于简单工厂)负责烧菜(生产的对象) ///
class Customer
{ static void Main(string[] args)
{ // 客户想点一个西红柿炒蛋
Food food1 = FoodSimpleFactory.CreateFood(“西红柿炒蛋”);
food1.Print(); // 客户想点一个土豆肉丝
Food food2 = FoodSimpleFactory.CreateFood(“土豆肉丝”);
food2.Print();
Console.Read();
}
} /// <summary>
/// 菜抽象类 /// </summary>
public abstract class Food
{ // 输出点了什么菜
public abstract void Print();
} /// <summary>
/// 西红柿炒鸡蛋这道菜 /// </summary>
public class TomatoScrambledEggs : Food
{ public override void Print()
{
Console.WriteLine("一份西红柿炒蛋!");
}
} /// <summary>
/// 土豆肉丝这道菜 /// </summary>
public class ShreddedPorkWithPotatoes : Food
{ public override void Print()
{
Console.WriteLine("一份土豆肉丝");
}
} /// <summary>
/// 简单工厂类, 负责 炒菜 /// </summary>
public class FoodSimpleFactory
{ public static Food CreateFood(string type)
{
Food food \= null; if (type.Equals("土豆肉丝"))
{
food\= new ShreddedPorkWithPotatoes();
} else if (type.Equals("西红柿炒蛋"))
{
food\= new TomatoScrambledEggs();
} return food;
}
}
看完简单工厂模式的实现之后,你和你的小伙伴们肯定会有这样的疑惑(因为我学习的时候也有)——这样我们只是把变化移到了工厂类中罢了,好像没有变化的问题,因为如果客户想吃其他菜时,此时我们还是需要修改工厂类中的方法(也就是多加case语句,没应用简单工厂模式之前,修改的是客户类)。我首先要说:你和你的小伙伴很对,这个就是简单工厂模式的缺点所在(这个缺点后面介绍的工厂方法可以很好地解决),然而,简单工厂模式与之前的实现也有它的优点:
虽然上面已经介绍了简单工厂模式的缺点,下面还是总结下简单工厂模式的缺点:
了解了简单工厂模式之后的优缺点之后,我们之后就可以知道简单工厂的应用场景了:
简单工厂模式又叫静态方法模式(因为工厂类都定义了一个静态方法),由一个工厂类根据传入的参数决定创建出哪一种产品类的实例(通俗点表达:通过客户下的订单来负责烧那种菜)。简单工厂模式的UML图如下:
介绍完了简单工厂模式之后,我学习的时候就像:.NET类库中是否有实现了简单工厂模式的类呢?后面确实有,.NET中System.Text.Encoding类就实现了简单工厂模式,该类中的**GetEncoding(int codepage)就是工厂方法,**具体的代码可以通过Reflector反编译工具进行查看,下面我也贴出该方法中部分代码:
public static Encoding GetEncoding(int codepage)
{
Encoding unicode = null; if (encodings != null)
{
unicode = (Encoding) encodings[codepage];
} if (unicode == null)
{ object obj2; bool lockTaken = false; try {
Monitor.Enter(obj2 = InternalSyncObject, ref lockTaken); if (encodings == null)
{
encodings = new Hashtable();
}
unicode = (Encoding) encodings[codepage]; if (unicode != null)
{ return unicode;
} switch (codepage)
{ case 0:
unicode = Default; break; case 1: case 2: case 3: case 0x2a: throw new ArgumentException(Environment.GetResourceString(“Argument_CodepageNotSupported”, new object[] { codepage }), “codepage”); case 0x4b0:
unicode = Unicode; break; case 0x4b1:
unicode = BigEndianUnicode; break; case 0x6faf:
unicode = Latin1; break; case 0xfde9:
unicode = UTF8; break; case 0x4e4:
unicode = new SBCSCodePageEncoding(codepage); break; case 0x4e9f:
unicode = ASCII; break; default:
unicode = GetEncodingCodePage(codepage); if (unicode == null)
{
unicode = GetEncodingRare(codepage);
} break;
}
encodings.Add(codepage, unicode); return unicode;
}
}
View Code
.NET 中Encoding的UML图为:
Encoding类中实现的简单工厂模式是简单工厂模式的一种演变,此时简单工厂类由抽象产品角色扮演,然而.NET中Encoding类是如何解决简单工厂模式中存在的问题的呢(即如果新添加一种编码怎么办)?在GetEncoding方法里的switch函数有如下代码:
switch (codepage)
{
……. default:
unicode = GetEncodingCodePage(codepage); if (unicode == null)
{
unicode = GetEncodingRare(codepage); //当编码很少见时
} break;
……
}
在GetEncodingRare方法里有一些不常用编码的实例化代码,微软正式通过这个方法来解决新增加一种编码的问题。(其实也就是列出所有可能的编码情况),微软之所以以这样的方式来解决这个问题,可能是由于现在编码已经稳定了,添加新编码的可能性比较低,所以在.NET 4.5仍然未改动这部分代码。
到这里,简单工厂模式的介绍都到这里了,后面将介绍工厂方法模式来解决简单工厂模式中存在的问题。
本专题中的全部源码:简单工厂模式源码
Composite,组合模式:将对象组合成树形结构以表示部分整体的关系,Composite使得用户对单个对象和组合对象的使用具有一致性。
http://www.cnblogs.com/zhili/p/CompositePattern.html
http://www.cnblogs.com/PatrickLiu/p/7743118.html
在面向对象程序设计过程中,有时会面临要创建大量相同或相似对象实例的问题。创建那么多的对象将会耗费很多的系统资源,它是系统性能提高的一个瓶颈。例如,围棋和五子棋中的黑白棋子,图像中的坐标点或颜色,局域网中的路由器、交换机和集线器,教室里的桌子和凳子等。这些对象有很多相似的地方,如果能把它们相同的部分提取出来共享,则能节省大量的系统资源,这就是享元模式的产生背景。
享元(Flyweight)模式的定义:运用共享技术来有效地支持大量细粒度对象的复用。它通过共享已经存在的对象来大幅度减少需要创建的对象数量、避免大量相似类的开销,从而提高系统资源的利用率。
享元模式的主要优点是:相同对象只要保存一份,这降低了系统中对象的数量,从而降低了系统中细粒度对象给内存带来的压力。
其主要缺点是:
享元模式中存在以下两种状态:
享元模式的主要角色有如下:
下图是享元模式的结构图。图中的 UnsharedConcreteFlyweight 是非享元角色,里面包含了非共享的外部状态信息 info;而 Flyweight 是抽象享元角色,里面包含了享元方法 operation(UnsharedConcreteFlyweight state),非享元的外部状态以参数的形式通过该方法传入;ConcreteFlyweight 是具体享元角色,包含了关键字 key,它实现了抽象享元接口;FlyweightFactory 是享元工厂角色,它逝关键字 key 来管理具体享元;客户角色通过享元工厂获取具体享元,并访问具体享元的相关方法。
享元模式的实现代码如下:
1 | class Program |
程序运行结果如下:
1 | 具体享元a被创建! |
享元模式是通过减少内存中对象的数量来节省内存空间的,所以以下几种情形适合采用享元模式:
在前面介绍的享元模式中,其结构图通常包含可以共享的部分和不可以共享的部分。在实际使用过程中,有时候会稍加改变,即存在两种特殊的享元模式:单纯享元模式和复合享元模式,下面分别对它们进行简单介绍。
在有些情况下,一个客户不能或者不想直接访问另一个对象,这时需要找一个中介帮忙完成某项任务,这个中介就是代理对象。
由于某些原因需要给某对象提供一个代理以控制对该对象的访问。这时,访问对象不适合或者不能直接引用目标对象,代理对象作为访问对象和目标对象之间的中介。
主要优点有:
主要缺点有:
代理模式的结构比较简单,主要是通过定义一个继承抽象主题的代理来包含真实主题,从而实现对真实主题的访问。
代理模式的主要角色如下:
其结构图如图所示:
代理模式的实现代码如下:
1 |
|
程序运行的结果如下:
1 | 访问真实主题之前的预处理。 |
前面分析了代理模式的结构与特点,现在来分析以下的应用场景:
智能指引的典型用途包括:
在前面介绍的代理模式中,代理类中包含了对真实主题的引用,这种方式存在两个缺点:
采用动态代理模式可以解决以上问题(如 SpringAOP),C#中可以使用RealProxy实现动态代理,有两种方法:
第一种:只使用RealProxy,不能代理带out参数的方法(可能是我没找到),代码如下:
1 | class Program |
第二种:使用RealProxy、MarshalByRefObject,可以代理带out参数的方法,代码如下:
1 |
|
在现实生活中,常常存在办事较复杂的例子,如办房产证或注册一家公司,有时要同多个部门联系,这时要是有一个综合部门能解决一切手续问题就好了。
软件设计也是这样,当一个系统的功能越来越强,子系统会越来越多,客户对系统的访问也变得越来越复杂。这时如果系统内部发生改变,客户端也要跟着改变,这违背了“开闭原则”,也违背了“迪米特法则”,所以有必要为多个子系统提供一个统一的接口,从而降低系统的耦合度,这就是外观模式的目标。
客户去当地房产局办理房产证过户要遇到的相关部门:
外观(Facade)模式的定义:是一种通过为多个复杂的子系统提供一个一致的接口,而使这些子系统更加容易被访问的模式。该模式对外有一个统一接口,外部应用程序不用关心内部子系统的具体的细节,这样会大大降低应用程序的复杂度,提高了程序的可维护性。
外观(Facade)模式是“迪米特法则”的典型应用,它有以下主要优点:
外观(Facade)模式的主要缺点如下:
外观(Facade)模式的结构比较简单,主要是定义了一个高层接口。它包含了对各个子系统的引用,客户端可以通过它访问各个子系统的功能。
外观(Facade)模式包含以下主要角色:
其结构图如图所示:
外观模式的实现代码如下:
1 | class Program |
程序运行结果如下:
1 | 子系统01的Method1()被调用! |
通常在以下情况下可以考虑使用外观模式:
在外观模式中,当增加或移除子系统时需要修改外观类,这违背了“开闭原则”。如果引入抽象外观类(或接口),则在一定程度上解决了该问题,其结构图如图所示:
在现实生活中,存在很多“部分-整体”的关系,例如,大学中的部门与学院、总公司中的部门与分公司、学习用品中的书与书包、生活用品中的衣月艮与衣柜以及厨房中的锅碗瓢盆等。
在软件开发中也是这样,例如,文件系统中的文件与文件夹、窗体程序中的简单控件与容器控件等。对这些简单对象与复合对象的处理,如果用组合模式来实现会很方便。
组合(Composite)模式的定义:有时又叫作部分-整体模式,它是一种将对象组合成树状的层次结构的模式,用来表示“部分-整体”的关系,使用户对单个对象和组合对象具有一致的访问性。
组合模式的主要优点有:
其主要缺点是:
组合模式包含以下主要角色:
组合模式分为透明式的组合模式和安全式的组合模式。
假如要访问集合 c0={leaf1,{leaf2,leaf3}} 中的元素,其对应的树状图如图所示:
下面给出透明式的组合模式的实现代码,安全式的组合模式与之类似:
1 | class Program |
程序运行结果如下:
1 | 树叶1:被访问! |
前面分析了组合模式的结构与特点,下面分析它适用的以下应用场景:
如果对前面介绍的组合模式中的树叶节点和树枝节点进行抽象,也就是说树叶节点和树枝节点还有子节点,这时组合模式就扩展成复杂的组合模式了,如 Java AWT/Swing 中的简单组件 JTextComponent 有子类 JTextField、JTextArea,容器组件 Container 也有子类 Window、Panel。复杂的组合模式的结构图如图所示:
在现实生活中,常常需要对现有产品增加新的功能或美化其外观,如房子装修、相片加相框等。
在软件开发过程中,有时想用一些现存的组件。这些组件可能只是完成了一些核心功能。但在不改变其结构的情况下,可以动态地扩展其功能。所有这些都可以釆用装饰模式来实现。
装饰(Decorator)模式的定义:指在不改变现有对象结构的情况下,动态地给该对象增加一些职责(即增加其额外功能)的模式,它属于对象结构型模式。
装饰(Decorator)模式的主要优点有:
其主要缺点是:装饰模式增加了许多子类,如果过度使用会使程序变得很复杂。
通常情况下,扩展一个类的功能会使用继承方式来实现。但继承具有静态特征,耦合度高,并且随着扩展功能的增多,子类会很膨胀。如果使用组合关系来创建一个包装对象(即装饰对象)来包裹真实对象,并在保持真实对象的类结构不变的前提下,为其提供额外的功能,这就是装饰模式的目标。
装饰模式主要包含以下角色:
装饰模式的结构图如图所示:
装饰模式的实现代码如下:
1 | class Program |
程序运行结果如下:
1 | 创建具体构件角色 |
装饰模式通常在以下几种情况使用:
Java的java.io包和.NET的Stream类都使用了该模式。我不会就它们的实现谈论很多细节。.NET中,Stream是一个抽象类,提供了基本的行为(如Component),从抽象类Stream继承来的类FileStream,MemoryStream是ConcreteCompents,类BufferedStream,CryptoStream等是ConcreteDecorators。你能清楚地认识到它们同样忽略了Decorator。
装饰模式所包含的 4 个角色不是任何时候都要存在的,在有些应用环境下模式是可以简化的,如以下两种情况: