需要知道的面向对象设计的基本原则

本文探讨了面向对象设计中的四个核心原则:单一责任原则、开闭原则、里氏替换原则和接口隔离原则。单一责任原则强调一个类应只有一个职责,以提高内聚性和降低耦合。开闭原则指出模块应开放扩展但关闭修改,通过继承或组合实现。里氏替换原则确保子类可以替换其基类,保持代码的稳定性和可扩展性。接口隔离原则提倡接口应为客户端定制,避免不必要的依赖。了解并应用这些原则可以提升软件的可维护性和可扩展性。
摘要由CSDN通过智能技术生成

单一责任原则

单一责任原则规定:

一个班级应该只有一个责任。

类使用其函数或契约(以及数据成员帮助函数)来履行其职责。

以下面的示例类为例:

ClassSimulation{

PublicLoadSimulationFile()

PublicSimulate()

PublicConvertParams()

}

这个类处理两个责任。首先,这个类正在加载模拟数据,其次,它正在执行模拟算法(使用Simulate和ConvertParams 职能)。

类使用一个或多个函数来履行职责。在上面的示例中,加载模拟数据是一项责任,而执行模拟则是另一项责任。加载模拟数据需要一个函数(即LoadSimationFile)。其余两个函数需要执行模拟。

我怎么知道我们班有多少责任?把“改变的理由”看作类似于责任。因此,寻找类更改的所有原因。如果有一个以上的原因改变一个类,那么这意味着这个类不遵循单一责任原则。

在上面的示例类中,这个类不应该包含LoadSimulationFile 函数(或加载模拟数据责任)。如果我们创建一个单独的类来加载模拟数据,那么这个类就不会违反SRP。

一个类只能有一个责任。你怎么能用这么严格的规则来设计软件呢?

让我们考虑另一个与SRP密切相关的原则:高内聚力。高内聚力给你一个主观的尺度,而不是一个客观的尺度,例如SRP。很低的凝聚力意味着一个班级正在履行许多责任。例如,一个类负责的责任超过10项。低衔接意味着一个班级大约完成5个责任,适度衔接意味着一个班级完成3个责任。高凝聚力意味着一个班级在履行一个单一的责任。因此,设计时的经验法则是争取高度的凝聚力。

这里应该讨论的另一个原则是低耦合。这一原则规定,人们应该分配责任,以使类之间的依赖性保持在较低水平。再次考虑上面的示例类。在应用SRP和高内聚原理后,我们决定建立一个单独的类来处理仿真文件。通过这种方式,我们创建了两个相互依赖的类。

似乎应用高内聚力使我们违背了低耦合的原则。这个级别的耦合被允许作为目标,以最小化耦合,但不允许联轴器。在创建面向对象的设计时,某种程度的耦合是正常的,在这种设计中,任务是通过对象的协作来完成的。

另一方面,考虑一个GUI类,它连接到数据库,通过HTTP处理远程客户端,并处理屏幕布局。这个GUI类依赖于太多的类。这个GUI类显然违反了低耦合原则。如果不涉及所有相关类,则不能重用此类。对数据库组件的任何更改都会导致GUI类的更改。

开闭原理

“开放-封闭原则”规定:

软件模块(可以是类或方法)应该开放供扩展,但关闭以进行修改。

换句话说,您不能更新已经为项目编写的代码,但可以向项目添加新代码。

有两种方法可以应用开闭原理.您可以通过继承或组合应用此原则。

下面是使用继承应用开放关闭原则的示例:

ClassDataStream{

Publicbyte[]Read()

}

ClassNetworkDataStream:DataStream{

Publicbyte[]Read(){

//Read from the network

}

}

ClassClient{

PublicvoidReadData(DataStreamds){

ds.Read();

}

}

在本例中,客户端读取数据(ds.Read())来自网络流。如果我想扩展客户机类的功能以从另一个流(例如pci数据流)读取数据,那么我将类的另一个子类。DataStream类,如下面的清单所示:

ClassPCIDataStream:DataStream{

Publcbyte[]Read(){

//Read data from PCI

}

}

在这种情况下,客户端代码将在没有任何错误的情况下工作。客户端类知道基类,并且我可以传递以下两个子类中任何一个的对象DataStream。这样,客户端就可以在不知道底层子类的情况下读取数据。这是在没有改性任何现存的密码。

我们可以使用组合来应用这个原则,还有其他的方法和设计模式来应用这个原则。本文将讨论这些方法中的一些。

您是否必须将此原则应用于您编写的每一段代码?没有。这是因为大部分代码不会改变。您只需要在那些您怀疑代码将来会发生变化的情况下,战略性地应用这个原则。

Liskov代换原理

Liskov替代原则规定:

派生类必须是它们的基类的替代类。

另一种看待这个定义的方法是抽象(接口或抽象类)应该是足够的为了一个客户。

为了详细说明,让我们考虑一个例子,下面是一个接口,其清单如下:

PublicInterfaceIDevice{

VoidOpen();

VoidRead();

VoidClose();

}

此代码表示数据采集设备的抽象。数据采集设备因其接口类型不同而不同。数据采集设备可以使用USB接口、网络接口(TCP或UDP)、PCI快速接口或任何其他计算机接口。然而,iDevice的客户端不需要知道他们使用的是哪种设备。这使程序员在不改变依赖iDevice接口的代码的情况下,能够灵活地适应新设备。

当只有两个实现iDevice接口的具体类时,让我们来了解一下历史,如下所示:

publicclassPCIDevice:IDevice{

publicvoidOpen(){

// Device specific opening logic

  }

publicvoidRead(){

// Reading logic specifi

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值