如何編寫優雅的代碼:07. 設計模式應用案例(下)

前文用C#代碼實現了Facade模式、Adapter模式、Strategy模式、Bridge模式和Abstract Factory模式解決實際業務需求。本文將繼續以C#代碼爲例,實現我在前面介紹的11個模式中剩下的6個模式:Decorator模式、Observer模式、Template Method模式、Singleton模式、Factory Method模式和Prototype模式。按照實現方法的不一樣,該11個模式可分紅三類:建立型模式(Abstract Factory, Singleton, Factory Method, Prototype)、結構型模式(Adapter, Bridge, Decorator)和行爲型模式(Strategy, Observer, Template Method)。html

.Decorator模式數據庫

業務場景:在中國銷售的一塊手錶,基本配置是顯示北京時間,但也提供帶有高級功能的配置。如:中端配置支持顯示當前時區下的日期、高端配置支持第二時區(具體能夠用戶設置)。採用Decorator模式實現的代碼以下:api

namespace PartternCase
{
    public abstract class AbstractWatch
    {//Component in UML
        public abstract void StartWork();
    }

    public class Watch : AbstractWatch
    {//ConcreteComponent in UML
        public override void StartWork()
        {
            //Show Beijing time
        }
    }

    public abstract class WatchDecorator : AbstractWatch
    {//Decorator in UML
        protected AbstractWatch Watch { get; set; }
        protected WatchDecorator(AbstractWatch watch)
        {
            Watch = watch;
        }
    }

    public class ShowDateDecorator : WatchDecorator
    {//ConcreteDecoratorA in UML
        public ShowDateDecorator(AbstractWatch watch)
            : base(watch)
        {
        }

        public override void StartWork()
        {
            Watch.StartWork();
            //Show date of current time zone
        }
    }

    public class ShowSecTimeZoneDecorator : WatchDecorator
    {//ConcreteDecoratorB in UML
        public ShowSecTimeZoneDecorator(AbstractWatch watch)
            : base(watch)
        {
        }

        public override void StartWork()
        {
            Watch.StartWork();
            // Show time of sencond timezone
        }
    }

    public class Client
    {//How to use decorator pattern
        public void ChooseWatch()
        {
            var watch = new Watch();//Basic function
            var middleWatch = new ShowDateDecorator(watch);//Middle: contain show date function
            var advanceWatch = new ShowSecTimeZoneDecorator(middleWatch);//Advance: contain show date and second time zone function
        }
    }
}

.Observer模式ide

業務場景:盛天公司內部的報銷有嚴格的審批流程,爲提升審批效率,當員工提交報銷單時,須要向具備審批權限的領導自動發送申請審批的郵件(固然,除報銷單外,領導還會收到其餘類型的審批郵件)。採用Observer模式實現的代碼以下:ui

namespace PartternCase
{
    public abstract class Report
    {//Subject in UML
        public string Status { get; set; }
        protected IList<Employee> Employees { get; set; }
        public void Attach(Employee employee)
        {
            Employees = Employees ?? new List<Employee>();
            Employees.Add(employee);
        }

        public void Detach(Employee employee)
        {
            if (Employees == null) { return; }
            Employees.Remove(employee);
        }

        public void Notify(Report report)
        {
            if (Employees == null) { return; }
            foreach (var employee in Employees)
            {
                employee.HandleReportSubmit(report);
            }
        }
    }

    public class ExpenseReport : Report
    {//ConcreteSubject in UML
        public void Submit()
        {
            Status = "Report Submited";
            Notify(this);
        }
    }

    public abstract class Employee
    {//Observer in UML
        public abstract void HandleReportSubmit(Report report);
    }

    public class Boss : Employee
    {//ConcreteObserver in UML
        public string Status { get; set; }
        public override void HandleReportSubmit(Report report)
        {
            // Send email to this boss by smtp server
            Status = report.Status;
        }
    }

    public class Client
    {//How to use observer pattern
        public void Observer()
        {
            var boss1 = new Boss();
            var boss2 = new Boss();
            var expense = new ExpenseReport();
            expense.Attach(boss1);
            expense.Attach(boss2);
            expense.Submit();
        }
    }
}

.Template Method模式this

業務場景:聖象飲料公司生產牛奶和礦泉水兩種飲料。運營過程都分爲生產和銷售兩個環節,但兩種飲料的生產和銷售方式不相同。如銷售方式:牛奶天天經過送貨員送貨上門,礦泉水經過各大超市銷售。採用Template Method模式實現的代碼以下:spa

namespace PartternCase
{
    public abstract class DrinkOperation
    {//AbstractClass in UML
        public void Perform()
        {//Interface for client call
            Product();
            Sales();
        }

        protected abstract void Product();
        protected abstract void Sales();
    }

    public class MilkOperation : DrinkOperation
    {//ConcreteClass in UML
        protected override void Product()
        {
            //Get raw material from milk station then process 
        }

        protected override void Sales()
        {
            //Sell by deliveryman
        }
    }

    public class WaterOperation : DrinkOperation
    {//ConcreteClass in UML
        protected override void Product()
        {
            //Get raw material from mountain then process 
        }

        protected override void Sales()
        {
            //Sell by supermarket
        }
    }
}

. Singleton模式code

業務場景:投資組合管理系統中常常會用到一些複雜的模型對投資組合的價值進行估值。這些計算模型每每都放在一個類中,互相之間沒有依賴關係。採用Singleton模式實現的代碼以下:orm

namespace PartternCase
{
    public class CalculationEngine
    {//Singleton in UML
        protected CalculationEngine() { }

        private static readonly CalculationEngine instance = new CalculationEngine();
        public static CalculationEngine GetInstance { get { return instance; } }// Interface for client call

        //Many calculation methods
    }
}

. Factory Method模式server

業務場景:聖天基金公司旗下的基金在向合夥人提款時,需根據合夥人類型不一樣(普通合夥人:GP、有限合夥人:LP)將提款數據存放在相應的合夥人類型中,而後保存。採用Factory Method模式實現的代碼以下:

namespace PartternCase
{
    public abstract class CapitalCall
    {//Creator in UML
        public abstract Partner BuildPartner();

        public void Perform()
        {
            var partner = BuildPartner();
            //Calculate amount of partner then save partner
        }
    }

    public class GpCapitalCall : CapitalCall
    {//ConcreteCreator in UML
        public override Partner BuildPartner()
        {
            return new GP();
        }
    }

    public class Partner
    {//Product in UML
        public decimal Amount { get; set; }
    }

    public class GP : Partner
    {//ConcreteProduct in UML
    }
}

. Prototype模式

業務場景:聖象飲料公司在查詢牛奶和礦泉水的季度銷量時,會分別針對Milk和Water數據庫表進行查詢,查詢條件除時間外從外部傳入,內部只設置時間條件,但不能改變傳入的查詢條件。下面將採用Prototype模式實現該業務場景:

namespace PartternCase
{
    public abstract class DrinkCriteria
    {//Prototype in UML
        public abstract string QueryTable { get; }
        public DateTime StartDate { get; set; }
        public DateTime EndDate { get; set; }
        //Other query fields

        public abstract DrinkCriteria Clone();
    }

    public class MilkCriteria : DrinkCriteria
    {//Concrete Prototype1 in UML
        public override string QueryTable { get { return "Milk"; } }

        public override DrinkCriteria Clone()
        {//This is shallow copy, in other case maybe need deep copy.
            return MemberwiseClone() as MilkCriteria;
        }
    }

    public class WaterCriteria : DrinkCriteria
    {//Concrete Prototype2 in UML
        public override string QueryTable { get { return "Water"; } }

        public override DrinkCriteria Clone()
        {
            return MemberwiseClone() as WaterCriteria;
        }
    }

    public class Client
    {//Client in UML
        //Set relative criteria at runtime
        private DrinkCriteria Criteria { get; set; }
        public void HowToUse()
        {
            var newCritera = Criteria.Clone();
            //newCritera.StartDate = 2013-1-1;
            //newCritera.EndDate = 2013-3-31;
            //Start to query user new criteria
        }
    }
}
相關文章
相關標籤/搜索