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

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

  • 相关阅读:
    【转】浅谈MVC与三层架构
    【转】小结登录的几种交互方式
    【转】 App架构设计经验谈:接口的设计
    【转】JS编码解码、C#编码解码
    jQuery 判断是否包含某个属性
    jQuery on()方法
    常用正则表达式大全
    Fiddler 抓取手机APP数据包
    [Asp.net]通过uploadify将文件上传到B服务器的共享文件夹中
    ★电车难题的n个坑爹变种
  • 原文地址:https://www.cnblogs.com/Cui-Shi-Yu/p/5756913.html
Copyright © 2020-2023  润新知