设计模式("大话设计模式"读书笔记 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),动态地给一个对象添加一些额外的职责,就增加功能来说,装饰模式比生成子类更加灵活。

总结:这个例子中,每一个类都形式自己的功能。他们公有的功能都写在了父类。可以实现动态的添加更多的衣服。

posted @ 2016-08-14 10:02  做一滴雨  阅读(2303)  评论(0编辑  收藏  举报