設計模式("大話設計模式"讀書筆記 C#實現)


前言:毫無疑問 ,學習一些設計模式,對我們的編程水平的提高幫助很大。寫這個博客的時候自己剛開始學習設計模式,難免有錯,歡迎評論指正。

        我學設計模式的第一本書是“大話設計模式”。

1.為什么要學設計模式?

設計模式的存在就是為了抵御需求變更。學會了這些思想,開始一個項目的時候考慮的更多,當用戶提出變更的時候項目改動更少。

2.怎么才能學會設計模式?

我不知道,不過輪子哥(vczh)文章中的一句話,我覺得對,就是:“設計模式就是因為情況復雜了所以才會出現的,所以我們只能通過復雜的程序來學習設計模式。你不管看別人的程序也好,自己寫程序練習也好,那必須要復雜,復雜到你不用設計模式就做不下去,這才能起到學習設計模式的作用”。所以,我准備選擇一些自己用到的設計模式,通過寫代碼的方式去熟悉它們。

一.簡單工廠模式(Simple Factory Pattern)

場景描述:制作一個計算器。

1.實現加減乘除。

2.以后有其它算法的時候,容易維護。

工廠類

 1 using System;
 2 using System.Collections.Generic;
 3 using System.Linq;
 4 using System.Text;
 5 using System.Threading.Tasks;
 6 //Author:cuishiyu
 7 //2016.08.13
 8 namespace OperationByFactory.Class
 9 {
10     //運算工廠類
11     class OperationFactory
12     {
13         public static Operation createOperation(string operate)
14         {
15             Operation oper = null;
16             switch (operate)
17             {
18                 case "+":
19                     oper = new OperationAdd();
20                     break;
21                 case "-":
22                     oper = new OperationSub();
23                     break;
24                 case "*":
25                     oper = new OperationMul();
26                     break;
27                 case "/":
28                     oper = new OperationDiv();
29                     break;
30             }
31             return oper;
32         }
33     }
34 }
View Code

運算類

 1 using System;
 2 using System.Collections.Generic;
 3 using System.Linq;
 4 using System.Text;
 5 using System.Threading.Tasks;
 6 //Author:cuishiyu
 7 //2016.08.13
 8 namespace OperationByFactory.Class
 9 {
10     //運算類
11     class Operation
12     {
13         private double _numberA = 0;
14         private double _numberB = 0;
15 
16         public double NumberA
17         {
18             get
19             {
20                 return _numberA;
21             }
22 
23             set
24             {
25                 _numberA = value;
26             }
27         }
28 
29         public double NumberB
30         {
31             get
32             {
33                 return _numberB;
34             }
35 
36             set
37             {
38                 _numberB = value;
39             }
40         }
41 
42         public virtual double GetResult()
43         {
44             double result = 0;
45             return result;
46         }
47     }
48 }
View Code

加減乘除類

 1 using System;
 2 using System.Collections.Generic;
 3 using System.Linq;
 4 using System.Text;
 5 using System.Threading.Tasks;
 6 //Author:cuishiyu
 7 //2016.08.13
 8 namespace OperationByFactory.Class
 9 {
10     //加法類
11     class OperationAdd:Operation
12     {
13         public override double GetResult()
14         {
15             return NumberA + NumberB;
16         }
17     }
18 }
View Code
 1 using System;
 2 using System.Collections.Generic;
 3 using System.Linq;
 4 using System.Text;
 5 using System.Threading.Tasks;
 6 //Author:cuishiyu
 7 //2016.08.13
 8 namespace OperationByFactory.Class
 9 {
10     //減法類
11     class OperationSub:Operation
12     {
13         public override double GetResult()
14         {
15             return  NumberA - NumberB;
16         }
17     }
18 }
View Code
 1 using System;
 2 using System.Collections.Generic;
 3 using System.Linq;
 4 using System.Text;
 5 using System.Threading.Tasks;
 6 //Author:cuishiyu
 7 //2016.08.13
 8 namespace OperationByFactory.Class
 9 {
10     //乘法類
11     class OperationMul:Operation
12     {
13         public override double GetResult()
14         {
15             return NumberA * NumberB;
16         }
17     }
18 }
View Code
 1 using System;
 2 using System.Collections.Generic;
 3 using System.Linq;
 4 using System.Text;
 5 using System.Threading.Tasks;
 6 //Author:cuishiyu
 7 //2016.08.13
 8 namespace OperationByFactory.Class
 9 {
10     //除法類
11     class OperationDiv:Operation
12     {
13         public override double GetResult()
14         {
15             if(NumberB== 0)
16                 throw new Exception("除數不能為0");
17             return NumberA / NumberB;
18         }
19     }
20 }
View Code

 總結:簡單工廠模式很簡單,重要的是。這個設計模式是怎么一步步形成的、和這樣做的好處有哪些。

1.可移植性號,無論是控制台程序,Windows程序,Web程序,都可以用這段代碼。

2.擴展性好,更安全,以后增加平方,立方,開根號等運算的時候,增加一個相應的類,然后再Switch里增加分支就好了。同時也不用擔心程序員修改原先寫好的加減乘除類,使得原先的代碼不會被有意或者無意的修改,所以更安全。

3.(1)編程盡可能避免重復的代碼。(2)對業務進行封裝,盡可能的讓業務邏輯和頁面邏輯分開,讓它們的耦合度下降,這樣更容易維護和擴展。

4.大家可以熟悉一下UML類圖,畫出來之后理解更直觀。

二.策略模式(strategy Pattern

場景描述:商場的收銀軟件,收銀員根據客戶所購買的商品單價和數量進行收費。

1.要考慮到打折的情況(比如過節打8折)。

2.要考慮滿A返B的情況(比如滿300返100)。

3.考慮以后發生其它情況是,盡量做到代碼容易更改,安全的更改。

注:部分代碼是偽代碼

抽象策略類

 1 using System;
 2 using System.Collections.Generic;
 3 using System.Linq;
 4 using System.Text;
 5 using System.Threading.Tasks;
 6 
 7 namespace PromotionByStrategy
 8 {
 9     //抽象策略類
10     abstract class CashSuper
11     {
12         public abstract double acceptCatch(double money);
13     }
14 }
View Code

返利收費子類

 1 using System;
 2 using System.Collections.Generic;
 3 using System.Linq;
 4 using System.Text;
 5 using System.Threading.Tasks;
 6 
 7 namespace PromotionByStrategy
 8 {
 9     //返利收費子類
10     class CashReturn : CashSuper
11     {
12         private double moneyCondition = 0.0d;
13         private double moneyReturn = 0.0d;
14         public CashReturn(string moneyCondition, string moneyReturn)
15         {
16             this.moneyCondition = double.Parse(moneyCondition);
17             this.moneyReturn = double.Parse(moneyReturn);
18         }
19         public override double acceptCatch(double money)
20         {
21             double result = money;
22             if (money >= moneyCondition)
23             {
24                 result = money - Math.Floor(money / moneyCondition) * moneyReturn;
25             }
26             return result;
27         }
28     }
29 }
View Code

打折收費子類

 1 using System;
 2 using System.Collections.Generic;
 3 using System.Linq;
 4 using System.Text;
 5 using System.Threading.Tasks;
 6 
 7 namespace PromotionByStrategy
 8 {
 9     //打折收費子類
10     class CashRebate : CashSuper
11     {
12         private double moneyRebate = 1d;
13 
14         //構造函數傳入打折信息
15         public CashRebate(string moneyRebate)
16         {
17             this.moneyRebate = double.Parse(moneyRebate);
18         }
19 
20         public override double acceptCatch(double money)
21         {
22             return money * moneyRebate;
23         }
24     }
25 }
View Code

正常收費子類

 1 using System;
 2 using System.Collections.Generic;
 3 using System.Linq;
 4 using System.Text;
 5 using System.Threading.Tasks;
 6 
 7 namespace PromotionByStrategy
 8 {
 9     //正常收費子類
10     class CashNormal : CashSuper
11     {
12         public override double acceptCatch(double money)
13         {
14             return money;
15         }
16     }
17 }
View Code

策略和簡單工廠的結合

 1 using System;
 2 using System.Collections.Generic;
 3 using System.Linq;
 4 using System.Text;
 5 using System.Threading.Tasks;
 6 
 7 namespace PromotionByStrategy
 8 {
 9     //策略和簡單工廠的結合
10     class CashContext
11     {
12         //收錢的父類
13         CashSuper cs = null;
14         
15         /// <summary>
16         /// 構造函數初始化收費類型對象
17         /// </summary>
18         /// <param name="type"></param>
19         public CashContext(string type)//傳入一個收費的類型
20         {
21             switch (type)//根據不同的類型實例化不同的收款算法對象
22             {
23                 case"正常收費":
24                      cs = new CashNormal();
25                     break;
26                 case "滿A減B":
27                     cs = new CashReturn("A", "B");
28                     break;
29                 case "打X折":
30                     cs = new CashRebate("0.X");
31                     break;    
32             }
33         }
34         
35         public double GetResult(double money)
36         {
37             return cs.acceptCatch(money);
38         }
39     }
40 }
View Code

客戶端的主要程序

1  double tatal = 0.0d;
2         //客戶端的主要程序
3         //傳入算法,和價格*數量,得到應收的錢
4         public void btnOK_Click()
5         {
6             CashContext csuper = new CashContext("傳入收款的算法");
7             double totalPrices = 0.0d;
8             totalPrices = csuper.GetResult(Convert.ToDouble("價格*數量"));
9         }
View Code

總結:在分析一個項目中,遇到不同的時間應用不同的業務規則,就可以考慮使用策略模式處理這種變化的可能性。這個代碼還可以優化,后面會用反射進行優化

三.單一職責原則(SRP)

注:三、四、五主要分享設計模式中用到的一些原則

就一個類而言,因該僅有一個引起它變化的原因。一個類只行使一個功能,后面維護的時候會方便許多。

四.開放-封閉原則(The Open-Closeed Principle)

對軟件實體來說(類、模塊。函數)都要求滿足:

兩大特征:對擴張是開放的(Open for extension),對更改是封閉的(Closed for modification)。

在具體的實現過程中,可按照下面做:

1.我們在最初編碼的時候,假設變化不會發生。當發生變化的時候,我們就創建抽象來隔離以后發生的同類變化。

2.當面對需求的時候,對程序的改動,是通過增加代碼而不是修改現有的代碼實現。

3.拒絕不成熟的抽象,和抽象本身同樣重要。

五.依賴倒轉原則

1.依賴倒轉原則:抽象不應該依賴細節,細節應該依賴抽象。

簡單解釋就是,針對接口編程而不是針對實現編程。

A.高模塊不應該依賴低層模塊。兩個都應該依賴抽象。

B.抽象不應該依賴細節,細節應該依賴抽象。

2.里氏代換原則:子類型必須能夠替換掉他們的父類型。

簡單解釋就是,一個軟件實體如果使用的是一個父類的話,那么一定使用於其子類,而且它察覺不出父類對象和子類對象的區別。

也就是說,在軟件里面,把父類都替換成它的子類,程序行為沒有變化。

 六.裝飾模式

場景描述:寫一個給人搭配不同服飾的系統,類似QQ秀,或者游戲皮膚之類的。

Person類

 1 using System;
 2 using System.Collections.Generic;
 3 using System.Linq;
 4 using System.Text;
 5 using System.Threading.Tasks;
 6 
 7 namespace DressByDecorator
 8 {
 9     //Person類
10     class Person
11     {
12         public Person()
13         { }
14 
15         private string name;
16 
17         public Person(string name)
18         {
19             this.name = name;
20         }
21 
22         public virtual void Show()
23         {
24             Console.WriteLine("裝扮的{0}",name);
25         }
26     }
27 }
View Code

服飾類,繼承Person類

 1 using System;
 2 using System.Collections.Generic;
 3 using System.Linq;
 4 using System.Text;
 5 using System.Threading.Tasks;
 6 
 7 namespace DressByDecorator
 8 {
 9     //服飾類
10     class Finery : Person
11     {
12         protected Person componnet;
13 
14         //打扮
15         public void Decorate(Person component)
16         {
17             this.componnet = component;
18         }
19 
20         public override void Show()
21         {
22             if (componnet != null)
23             {
24                 componnet.Show();
25             }
26         }
27     }
28 }
View Code

具體的服飾類,下面舉兩個例子。

鞋子類,繼承服飾類。

 1 using System;
 2 using System.Collections.Generic;
 3 using System.Linq;
 4 using System.Text;
 5 using System.Threading.Tasks;
 6 
 7 namespace DressByDecorator
 8 {
 9     //鞋子類
10     class Shose:Finery
11     {
12         public override void Show()
13         {
14             Console.WriteLine("鞋子");
15             base.Show();
16         }
17     }
18 }
View Code

T恤類,繼承服飾類。

 1 using System;
 2 using System.Collections.Generic;
 3 using System.Linq;
 4 using System.Text;
 5 using System.Threading.Tasks;
 6 
 7 namespace DressByDecorator
 8 {
 9     //T恤類
10     class TShirts:Finery
11     {
12         public override void Show()
13         {
14             Console.WriteLine("T恤");
15             base.Show();
16         }
17     }
18 }
View Code

下面是main函數里的實現

 1 using System;
 2 using System.Collections.Generic;
 3 using System.Linq;
 4 using System.Text;
 5 using System.Threading.Tasks;
 6 
 7 namespace DressByDecorator
 8 {
 9     //Person類
10     class Person
11     {
12         public Person()
13         { }
14 
15         private string name;
16 
17         public Person(string name)
18         {
19             this.name = name;
20         }
21 
22         public virtual void Show()
23         {
24             Console.WriteLine("裝扮的{0}",name);
25         }
26     }
27 }
View Code

裝飾模式(Decorator),動態地給一個對象添加一些額外的職責,就增加功能來說,裝飾模式比生成子類更加靈活。

總結:這個例子中,每一個類都形式自己的功能。他們公有的功能都寫在了父類。可以實現動態的添加更多的衣服。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM