[有格式的原文请到https://www.cnc6.cn/c六大设计原则/文末下载]

软件设计原则常见的有6大原则,分别为:

①单一职责原则;

②开闭原则;

③依赖倒置原则;

④里氏替换原则;

⑤接口隔离原则;

⑥迪米特法则。

使用C#编程方式,并结合仪器(Instrument)编程,对以上设计原则进行讲解。

一、单一职责原则

简述:类职责要单一,不能有多个职责,具有多个职责的类要进行拆分,形成单一职责的类。

C#代码如下:

class DCPowerSupply

{

public void On() { }

public void Off() { }

public double Voltage { set; get; }

public double Current { set; get; }

public void Record(string content)

{

//记录操作

}

}

以上代码中,函数Off、On、Voltage、Current都是属于DCPowerSupply类的职责,但函数Record并不属于DCPowerSupply的职责,因此,需要将Record函数重新形成一个新类,并应用到该类中,新修改的C#代码如下:

class DCPowerSupply

{

public void On() { }

public void Off() { }

public double Voltage { set; get; }

public double Current { set; get; }

}

class Log

{

public void Record(string content)

{

//记录操作

}

}

客户端代码如下:

class Program

{

static void Main(string[] args)

{

DCPowerSupply dcPowerSupply = new DCPowerSupply();

dcPowerSupply.Voltage = 5;

dcPowerSupply.On();

Log log = new Log();

log.Record($"DCPowerSupply:{dcPowerSupply.Voltage},On");

}

}

从以上代码可以看出,原本耦合性很强的DCPowerSupply中的函数Record,已经从该类中进行解耦,形成松耦合的代码,复用性更强。

二、开闭原则

简述:对类的操作,拓展的要开放,修改的要关闭,类一旦写好并运行OK,就不要轻易去变动它,利用面向对象编程的继承特性,可以很好地对所需要增加的功能进行拓展。

C#代码如下:

class ACPowerSupply

{

public void On() { }

public void Off() { }

public double Voltage { set; get; }

public double Current { set; get; }

}

现在需要在ACPowerSupply类加入测量功率因素(PowerFactor)的功能,如果像这样修改ACPowerSupply类,C#代码如下:

class ACPowerSupply

{

public void On() { }

public void Off() { }

public double Voltage { set; get; }

public double Current { set; get; }

public double PowerFactor { set; get; }

}

那就会违背了开闭原则,因ACPowerSupply类已经写好,如果要增加功能,可以新编写一个名为ACPowerSupplyEx的类,继承自ACPowerSupply,并在其中加入PowerFactor的功能即可。

C#代码如下:

class ACPowerSupplyEx:ACPowerSupply

{

public double PowerFactor { set; get; }

}

三、依赖倒置原则

简述:抽象不依赖于具体细节,具体细节依赖抽象,要面向抽象编程,不要面向实现编程。说的简单点,无论是变量声明、返回值、还是参数,其类型都是抽象的,而不是具体的。

鉴于以上特点:

①每个类尽量继承自接口或抽象类、或两者的结合体;

②每个类不应该从具体类派生;

③由于有使用继承,尽量参照里氏替换原则(以下第四点所述)。

C#代码如下:

class PowerSupply

{

public void On() { }

public void Off() { }

public double Voltage { set; get; }

public double Current { set; get; }

}

class DCPowerSupply: PowerSupply

{

public double Power { set; get; }

}

class ACPowerSupply: PowerSupply

{

public double PowerFactor { set; get; }

}

class PowerSupplySeller

{

public void Sell(ACPowerSupply powerSupply)

{

//卖AC电源

}

public void Sell(DCPowerSupply powerSupply)

{

//卖DC电源

}

}

客户端代码如下:

class Program

{

static void Main(string[] args)

{

PowerSupplySeller seller = new PowerSupplySeller();

seller.Sell(new ACPowerSupply());

//下次想卖DC电源产品,就不得不在PowerSupplySeller类写入一个重载版的Sell方法,违背了开闭原则

}

}

正确的C#代码如下(只需对public void Sell(ACPowerSupply powerSupply)进行修改即可):

class PowerSupplySeller

{

public void Sell(PowerSupply powerSupply)

{

//卖AC或DC电源

}

}

客户端代码如下:

class Program

{

static void Main(string[] args)

{

PowerSupplySeller seller = new PowerSupplySeller();

seller.Sell(new ACPowerSupply());

seller.Sell(new DCPowerSupply());

}

}

以上不仅仅体现在形参上,还体现在方法或属性的返回值、字段类型等。

四、里氏替换原则

简述:可以使用父类的类型来代替子类的类型,但不改变子类的行为,继承必须确保父类所拥有的性质在子类中仍然成立。

C#代码如下:

class Meter

{

public double Voltage

{

get

{

//模仿返回一个值,这里以5.01V为准

double value = 5.01;

Console.WriteLine($"DigitalMeter,Voltage:{value}");

return value;

}

}

public double Current

{

get

{

//模仿返回一个值,这里以1.001A为准

double value = 1.001;

Console.WriteLine($"DigitalMeter,Current:{value}");

return value;

}

}

}

class DigitalMeter: Meter

{

}

class DCPowerSupply : Meter

{

public double Voltage

{

get

{

//模仿返回一个值,这里以12.02V为准

double value = 12.02;

Console.WriteLine($"DCPowerSupply,Voltage:{value}");

return value;

}

}

public double Current

{

get

{

//模仿返回一个值,这里以2.002A为准

double value = 2.002;

Console.WriteLine($"DCPowerSupply,Current:{value}");

return value;

}

}

}

客户端代码如下:

class Program

{

static void Main(string[] args)

{

Meter meter1 = new DigitalMeter();

Meter meter2 = new DCPowerSupply();

var voltage1 = meter1.Voltage;

var voltage2 = meter2.Voltage;

var current1 = meter1.Current;

var current2 = meter2.Current;

}

}

运行结果如下:

从以上可以看出,本来为DCPowerSupply的类,既然输出了Meter的信息,这就违背了里氏替换原则。

新修改的代码如下:

interface IMeter

{

double Voltage { get; }

double Current { get; }

}

class Meter: IMeter

{

public double Voltage

{

get

{

//模仿返回一个值,这里以5.01V为准

double value = 5.01;

Console.WriteLine($"DigitalMeter,Voltage:{value}");

return value;

}

}

public double Current

{

get

{

//模仿返回一个值,这里以1.001A为准

double value = 1.001;

Console.WriteLine($"DigitalMeter,Current:{value}");

return value;

}

}

}

class DigitalMeter: Meter

{

}

class DCPowerSupply : IMeter

{

public double Voltage

{

get

{

//模仿返回一个值,这里以12.02V为准

double value = 12.02;

Console.WriteLine($"DCPowerSupply,Voltage:{value}");

return value;

}

}

public double Current

{

get

{

//模仿返回一个值,这里以2.002A为准

double value = 2.002;

Console.WriteLine($"DCPowerSupply,Current:{value}");

return value;

}

}

}

客户端代码如下:

class Program

{

static void Main(string[] args)

{

IMeter meter1 = new DigitalMeter();

IMeter meter2 = new DCPowerSupply();

var voltage1 = meter1.Voltage;

var voltage2 = meter2.Voltage;

var current1 = meter1.Current;

var current2 = meter2.Current;

}

}

运行结果如下:

从以上代码可以看出,用父类代替子类时,不能影响其子类的行为,否则,就违背了里氏替换原则。

五、接口隔离原则

简述:要让接口尽量简单,功能一致的可以写在仪器,与接口无关的必须重新写接口,也就是说,不要让接口变得臃肿。

C#代码如下:

interface IInstrument

{

void Write(string command);

string Read();

double Voltage { get; }

double Current { get; }

}

以上代码有两组,一组为Write、Read,另外一组为Voltage、Current,按照功能分类的话,Write、Read应属于端口的读写,而Voltage、Current则为电表的读电压、读电流,按照接口隔离原则,需要进行隔离。

修改后的代码如下:

interface IPort

{

void Write(string command);

string Read();

}

interface IMeter

{

double Voltage { get; }

double Current { get; }

}

六、迪米特法则

简述:类A、类B之间本身没有直接关联关系,那么就不能相互调用,可以通过第三个类(类C)进行间接调用,降低类A与类B的耦合性,提高模块的相对独立性。

C#代码如下:

class DCPowerSupply

{

public Port Port { set; get; }

public double Voltage

{

set

{

Port.Write($"Voltage:{value}");

}

get

{

return Convert.ToDouble(Port.Read());

}

}

public double Current

{

set

{

Port.Write($"Current:{value}");

}

get

{

return Convert.ToDouble(Port.Read());

}

}

public void On() { }

public void Off() { }

}

class Port

{

public void Write(string command)

{

}

public string Read()

{

return new Random().NextDouble().ToString();

}

}

以上代码,Port类与DCPowerSupply类进行了相互调用,耦合性很强,改变其中一个类的方法,对调用的那个类有很大的影响。

修改之后的代码如下:

class DCPowerSupply

{

public double Voltage { set; get; }

public double Current { set; get; }

public void On() { }

public void Off() { }

}

class Port

{

public void Write(string command)

{

}

public string Read()

{

return new Random().NextDouble().ToString();

}

}

class DCPowerSupplyWithPort

{

DCPowerSupply powerSupply;

Port port;

public DCPowerSupplyWithPort()

{

powerSupply = new DCPowerSupply();

port = new Port();

}

public double Voltage

{

set

{

port.Write($"Voltage:{value}");

}

get

{

return Convert.ToDouble(port.Read());

}

}

public double Current

{

set

{

port.Write($"Current:{value}");

}

get

{

return Convert.ToDouble(port.Read());

}

}

public void On()

{

powerSupply.On();

}

public void Off()

{

powerSupply.Off();

}

}

以上代码,可以将Port类与DCPowerSupply类进行分离,使用了第三个类DCPowerSupplyWithPort,使得Port类与DCPowerSupply类松耦合,独立性强,符合迪米特法则,同样,该法则还适用于三层架构。

c#六大设计原则(以仪器代码为例)的更多相关文章

  1. IOS设计模式的六大设计原则之开放-关闭原则(OCP,Open-Close Principle)

    定义 一个软件实体(如类.模块.函数)应当对扩展开放,对修改关闭. 定义解读 在项目开发的时候,都不能指望需求是确定不变化的,大部分情况下,需求是变化的.那么如何应对需求变化的情况?这就是开放-关闭原 ...

  2. PHP设计模式的六大设计原则

    PHP设计模式的六大设计原则 1 简介 软件设计最大的难题就是应对需求的变化,但是纷繁复杂的需求变化却是不可预料的.此时,我们可以通过六大设计原则良好的应对未来的变化. 2 讲解 2.1 单一职责原则 ...

  3. 十年阿里java架构师的六大设计原则和项目经验

      先看一幅图吧: 这幅图清晰地表达了六大设计原则,但仅限于它们叫什么名字而已,它们具体是什么意思呢?下面我将从原文.译文.理解.应用,这四个方面分别进行阐述. 1.单一职责原则(Single Res ...

  4. iOS----------设计模式的六大设计原则------>开放-关闭原则(OCP,Open-Close Principle)

    定义 一个软件实体(如类.模块.函数)应当对扩展开放,对修改关闭. 定义解读 在项目开发的时候,都不能指望需求是确定不变化的,大部分情况下,需求是变化的.那么如何应对需求变化的情况?这就是开放-关闭原 ...

  5. JAVA设计模式总结之六大设计原则

    从今年的七月份开始学习设计模式到9月底,设计模式全部学完了,在学习期间,总共过了两篇:第一篇看完设计模式后,感觉只是脑子里面有印象但无法言语.于是决定在看一篇,到9月份第二篇设计模式总于看完了,这一篇 ...

  6. 六大设计原则——单一职责原则【Single Responsibility Principle】

    声明:本文内容是从网络书籍整理而来,并非原创. 用户管理的例子 先看一张用户管理的类图:  再看一眼上面的图,思考:这样合理吗? 这个接口是一个很糟糕的设计! 用户的属性和行为竟然混合在一起!!! 正 ...

  7. SOLID 设计原则 In C# 代码实现

    [S] Single Responsibility Principle (单一职责原则) 认为一个对象应该仅只有一个单一的职责 namespace SingleResponsibilityPrinci ...

  8. Java六大设计原则

    类的设计原则     依赖倒置原则-Dependency Inversion Principle (DIP) 里氏替换原则-Liskov Substitution Principle (LSP) 接口 ...

  9. 六大设计原则(C#)

    为什么要有设计原则,我觉得一张图片就可以解释这一切 一.单一职责原则(SRP) 对于一个类而言,应该只有一个发生变化的原因.(单一职责不仅仅是指类) 如果一个模块需要修改,它肯定是有原因的,除此原因之 ...

随机推荐

  1. 做了一个浏览指定文件格式的 TreeView(方便查看Source目录下的源码)

    unit DirTreeView; interface uses   SysUtils, Classes, Controls, Forms, ComCtrls; type   TDirTreeView ...

  2. 如何自学PHP做一个网站 PHP可以做什么项目?网站 小程序 公众号能用PHP开发吗?

    很多想从事程序开发的人员,想自学一门语言,不知道从哪里下手学习,如何入门学习?今天我们就以PHP为例子,来讲述一下如何快速的学习一门开发语言,让你快速入门.PHP是一个什么语言?它能开发什么项目呢?下 ...

  3. apache虚拟主机防止php网页木马vhost.conf文件配置

    <VirtualHost *> DocumentRoot "/www/www.abc.com" ServerName www.abc.com ServerAlias a ...

  4. aspose授权亲测可用配套代码

    支持excel,word,ppt,pdf using Aspose.Cells; using Aspose.Words.Saving; using ESBasic; using OMCS.Engine ...

  5. spark 源码分析之四 -- TaskScheduler的创建和启动过程

    在 spark 源码分析之二 -- SparkContext 的初始化过程 中,第 14 步 和 16 步分别描述了 TaskScheduler的 初始化 和 启动过程. 话分两头,先说 TaskSc ...

  6. tomcat配置多个数据源

    应用场景: 公司tomcat服务器中运行着多个工程,工程链接的mysql数据库不同,所以每个工程的Spring总配置文件中都配置了数据源. 需求:   将数据源统一拿到tomcat中配置. 本来指派给 ...

  7. 【Spring源码解析】—— 策略模式在Spring中的应用

    一.         什么是策略模式 策略模式的定义/含义:策略本身就是为了实现某一个目标而采取的一种工作方式,因此只要能够达成目标,则采取哪一种策略都可以:因此多种实际的策略之间是相互平行的. 注意 ...

  8. Fiddler如何过滤无用的链接

    场景:现在是移动端的天下,测试过程中,抓包工具肯定必不可少,如何使用这里就不赘述,这里给大家讲述下如何过滤那些没有的链接,js ,png等无用的信息 工具:fiddler-use Filters功能: ...

  9. Postman接口测试_基本功能

    一.   安装与更新 1.安装的方式 方式1:chrome插件版本:chrome--->设置--->扩展程序: 方式2:native版本(具有更好的扩展性,推荐使用):https://ww ...

  10. 微服务-springboot打包

    idea打包方式: 打包前确认项目可以正常运行 一.File->Project Structure->Artifacts->点击 + ->JAR->From module ...