前文一共介绍了四人帮(Gang of Four)总结的的11个设计模式,对初学者而言,光看文字描述和UML类图略显抽象。本着Learning in Doing的原则,本文将举一些实际的业务需求场景,以C#代码为例,讲述在编程的过程中如何应用设计模式,实现模块间低耦合,高内聚,编写出优雅的代码。需说明的是,接下来的例子相对简单,省略了业务逻辑代码,目的是为了让大家专注于设计模式的应用,忽略业务逻辑本身的复杂性,毕竟本文的目的是加深对设计模式本身的理解。
一.Façade模式
业务场景:圣象饮料公司需汇总每个季度矿泉水的销量,并和竞争对手的销量进行比较,并且以季度报表的形式汇报管理层。当前的系统情况是:统计内部商品的销量由类SelfProduct、竞争对手商品的销量由类CompetitorProject负责,该需求用Facade模式实现如下:
namespace PartternCase { public class SelfProduct {//Class A in UML public decimal StatSales(DateTime start, DateTime end, string kind); } public class CompetitorProduct {//Class B in UML public decimal StatSales(DateTime start, DateTime end, string kind); } public class ReportFacade {//Facade in UML private SelfProduct Self { get; set; } private CompetitorProduct Competitor { get; set; } public ReportFacade(SelfProduct self, CompetitorProduct competitor) { Self = self; Competitor = competitor; } public Tuple<decimal, decimal> StatSelling(DateTime start, DateTime end) {//Interface for client call return Tuple.Create(Self.StatSales(start, end, "MineralWater"), Competitor.StatSales(start, end, "MineralWater")); } } }
二.Adapter模式
业务场景:需要提供一个快速创建Word文档的API,微软提供的Office对象模型太复杂,创建Word时需要传入太多的缺省参数。下面是用对象Adapter模式实现的代码(C#不支持多继承,在此不介绍类Adapter模式,况且也不推荐使用):
namespace PartternCase { public interface IWordAdapter {//Target in UML //Interface for client call void CreateWord(string filePath); } public class WordAdapter : IWordAdapter {//Adapter in UML public void CreateWord(string filePath) { Object Nothing = System.Reflection.Missing.Value; //MS default word creator is Adaptee Application wordApp = new Microsoft.Office.Interop.Word.ApplicationClass(); Document wordDoc = wordApp.Documents.Add(ref Nothing, ref Nothing, ref Nothing, ref Nothing); wordDoc.SaveAs(ref filePath, ref Nothing, ref Nothing, ref Nothing, ref Nothing, ref Nothing, ref Nothing, ref Nothing, ref Nothing, ref Nothing, ref Nothing, ref Nothing, ref Nothing, ref Nothing, ref Nothing, ref Nothing); wordDoc.Close(ref Nothing, ref Nothing, ref Nothing); wordApp.Quit(ref Nothing, ref Nothing, ref Nothing); } } }
三.Strategy模式
业务场景:假设用户熟悉每种排序算法的应用场景,需要在界面自己选择排序算法(众所周知,排序算法有很多种,各自适合不同的场景),将一组数字排序后,打印在窗口。采用策略模式实现的代码如下:
namespace PartternCase { public class SequencePrinter {//Context in UML private Sorter Sorter { get; set; } public SequencePrinter(Sorter sorter) {//Interface for client call
Sorter = sorter; } public void Perform(IList<int> sequences) {//Assign relative sorter by criteria at runtime context sequences = Sorter.Rank(sequences); foreach (var sequence in sequences) { Console.WriteLine("Number is " + sequence); } } } public abstract class Sorter {//Strategy in UML public abstract IList<int> Rank(IList<int> source); } public class BubbleSorter : Sorter {//ConcreteStrategyA in UML public override IList<int> Rank(IList<int> source); } public class QuickSorter : Sorter {//ConcreteStrategyB in UML public override IList<int> Rank(IList<int> source); } }
四.Bridge模式
业务场景:将上述Strategy模式的业务场景做一个扩展,正好就是采用Bridge模式的最佳场景,即:用户可以在界面选择外排序算法和打印终端,将一组数据排序后,打印到相应的终端上。采用Bridge模式的实现代码如下:
namespace PartternCase { public abstract class AbstractSequencePrinter {//Abstraction in UML protected Sorter Sorter { get; set; } protected AbstractSequencePrinter(Sorter sorter) {//Assign relative sorter by criteria at runtime context Sorter = sorter; } public abstract void Perform(IList<int> sequences); } public class ConsoleSequencePrinter : AbstractSequencePrinter {//RefinedAbstraction in UML public ConsoleSequencePrinter(Sorter sorter) : base(sorter) { } public override void Perform(IList<int> sequences) { sequences = Sorter.Rank(sequences); foreach (var sequence in sequences) { Console.WriteLine("Number is " + sequence); } } } public abstract class Sorter {//Implementor in UML public abstract IList<int> Rank(IList<int> source); } public class BubbleSorter : Sorter {//ConcreteImplementorA in UML public override IList<int> Rank(IList<int> source); } public class QuickSorter : Sorter {//ConcreteImplementorB in UML public override IList<int> Rank(IList<int> source); } }
五.Abstract Factory模式
业务场景:圣天基金公司旗下有两种私募基金产品:主基金(Master Fund)和子基金(Feeder Fund)。两种基金的提款(Capital Call)规则和分配(Distribution)规则都存在明显差异,要求主基金的提款规则只能和主基金的分配规则搭配使用,不允许混淆。采用Abstract Factory模式的实现代码如下:
namespace PartternCase { public abstract class AbstractFund {//Abstract Factory //Interface for client call public abstract CapitalCallRule CreateCallRule(); public abstract DistributionRule CreateDistribRule(); } public class MasterFund : AbstractFund {//ConcreteFactory1 in UML public override CapitalCallRule CreateCallRule() { return new MasterCallRule(); } public override DistributionRule CreateDistribRule() { return new MasterDistribRule(); } } public class FeederFund : AbstractFund {//ConcreteFactory2 in UML public override CapitalCallRule CreateCallRule() { return new FeederCallRule(); } public override DistributionRule CreateDistribRule() { return new FeederDistribRule(); } } public abstract class CapitalCallRule {//AbstractProductA in UML } public class MasterCallRule : CapitalCallRule {//ConcreteProductA1 in UML } public class FeederCallRule : CapitalCallRule {//ConcreteProductA2 in UML } public abstract class DistributionRule {//AbstractProductB in UML } public class MasterDistribRule : DistributionRule {//ConcreteProductB1 in UML } public class FeederDistribRule : DistributionRule {//ConcreteProductB2 in UML } }