软件实体(类、模块、函数等)应该是可以扩展的,同时还可以是不必修改的,更确切的说,函数实体应该:
(1)对扩展是开放的
当应用的需求变化时,我们可以对模块进行扩展,使其具有满足改变的新的行为。即:我们可以改变模块的功能
(2)对更改是封闭的
对模块进行扩展时,不必改动模块已有的源代码或二进制代码。
分析:
- 世界是变化的(而且变化很快),软件是对现实的抽象。---->软件必须能够扩展
。
- 如果任何修改都需要改变已经存在的代码,那么可能导致牵一发动全身现象,进而导致雪崩效应,使软件质量显著下降。
实现OCP的关键是抽象:
例1:既不开放也不封闭的Client:
问题:
client和server都是具体类,接口与实现没有实现分离。如果我们想要让client调用一个新的server类,那么我们不得不修改client的源代码。从而带来编译、链接、部署等一系列的问题。
-
class
client{
-
server& s;
-
public
:
-
client(server& SER):s(SER) {}
-
void
useServer(){
-
s.ServerFunc();
-
}
-
};
-
class
server{
-
int
serverData;
-
public
:
-
void
ServerFunc();
-
};
修改后的设计:
- 设计中ClientInterfece类是一个拥有抽象成员函数的抽象类。Client类使用一个抽象类,然而Client的对象却是用Server类的派生类的对象。
- 如果希望Client对象使用一个不同的服务器类,那么只需从ClientInterfece类派生一个新的类,无需对Client类做任何改动。
-
class
client{
-
ClientInterface& ci;
-
public
:
-
client(ClientInterface &
-
CI):ci(CI){}
-
void
useServer(){
-
ci.ServerFunc();
-
}
-
};
-
class
ClientInterface{
-
virtual
void
ServerFunc()=0;
-
};
-
class
server:
public
ClientInterface{
-
int
serverData;
-
public
:
-
void
ServerFunc();
-
};
问题:
为什么上述的ClientInterface这个类要取这么个名字,而不叫AbastractServer?
其实这里面蕴含了一个思想:
——client类中更多的描述了高层的策略,而Server类中是对这些策略的一种具体实现。
- 而接口是策略的一个组成部分,它与client端的关系更加密切。
- ClientInterface中定义了client期望Server做什么,而server具体类是对client这种要求的一种具体实现。
- OCP原则要求我们清晰地区分策略和策略的具体实现形式。允许扩展具体的实现形式(开放),同时将这种扩展与策略隔离开来,使其对上层的策略透明(封闭)。
例2:
-
-
emum ShapeType{circle,square};
-
struct
Shape{
-
ShapeType itsType;
-
};
-
-
struct
Circle{
-
ShapeType itsType;
-
double
itsRadius;
-
CPoint itscenter;
-
};
-
-
struct
Square{
-
ShapeType itsType;
-
double
itsSide;
-
CPoint itsTopLeft;
-
};
-
-
typedef
struct
Shape * ShapePointer;
-
void
DrawAllShapes(ShapePointer list[],
int
n){
-
int
i;
-
for
(i=0;i<n;i++){
-
struct
Shape* s=list[i];
-
switch
(s->itsType){
-
case
square:
-
s->Square();
-
break
;
-
case
circle:
-
s->DrawCircle();
-
break
;
-
}
-
}}
例2的问题:
这个程序不符合OCP,如果需要处理的几何图形中再加入“三角形”将引发大量的修改。
增加Triangle会导致Shape、Square、Circle以及DrawAllShapes的重新编译和部署
因为存在大量的既难以查找又难以理解的Switch和If语句,修改稍有不慎,程序就会莫明其妙的出错
想在一个程序中复用DrawAllShapes,都必须带上Circle、Square,即使那个程序不需要他们
例2 修改后的设计:
-
class
Shape{
-
public
:
-
virtual
void
Draw()
const
=0;
-
};
-
class
Square:
public
Shape{
-
public
:
-
virtual
void
Draw()
const
;
-
};
-
class
Circle:
public
Shape{
-
public
:
-
virtual
void
Draw()
const
;
-
};
-
void
DrawAllShapes(Vector<Shape*>&
-
list){
-
vector<Shape*>::iterator i;
-
for
(i=list.begin();i!=list.end();i++)
-
(*i)->Draw();
-
}
完全封闭了吗?
- 上述代码并不完全封闭——“如果我们希望正方形在所有圆之前绘制”会怎么样?——对绘图的顺序无法实现封闭
- 更糟糕的是,刚才的设计反而成为了实现“正方形在所有圆之前绘制”功能的障碍。
小结:
- 一般而言,无论模块多么“封闭”,都会存在一些无法对之封闭的变化
没有对所有变化的情况都封闭的模型
既然不可能完全封闭,我们必须有策略的对待此问题——对模型应该封闭那类变化作出选择,封闭最可能出现的变化
----这需要对领域的了解,丰富的经验和常识。
--------错误的判断反而不美,因为OCP需要额外的开销(增加复杂度)
----敏捷的思想——我们预测他们,但是直到我们发现他们才行动
OCP----封装思想的体现
对可变性的封装原则:
- 找到一个系统的可变因素,将之封装起来。
- 考虑你的设计中什么会发生变化-------对应思路:什么会导致设计改变
具体的:
-
一种可变性不应该散落在代码的很多角落里,而应被封装在一个对象里。(继承可看作封装变化的方法。)
-
一种可变性不应与另一种可变性混在一起。(继承层次不应太多。)
相应设计模式:
- Strategy
- Simple Factory
- Factory Method
- Abstract Factory
- Builder
- Bridge
- Façade
- Mediator
分享到:
相关推荐
开闭原则(Open-Closed Principle,OCP)的核心思想是:“软件实体(如类、模块、函数等)应当对扩展开放,对修改关闭”。这意味着,当需求改变时,我们应尽量通过扩展已有代码,而不是修改已有的代码来实现新功能。...
总之,开闭原则是软件设计的重要指导思想,它提倡通过合理的抽象和多态性来实现代码的灵活性和稳定性。在Java Web开发中,理解并遵循OCP原则,可以显著提升系统的可扩展性和可维护性,从而为项目带来长期的益处。
开闭原则(Open-Closed Principle,简称OCP)是面向对象设计中的一个核心原则,它在软件工程领域具有举足轻重的地位。该原则由 Bertrand Meyer 在其著作《Object-Oriented Software Construction》中提出,旨在提高...
在软件设计中,OCP 开闭原则是其中一个非常重要的设计原则。该原则定义了一个软件实体,如类、模块和函数应该对扩展开放,对修改关闭。也就是说,当软件需要变化时,应该尽量通过扩展软件实体的行为来实现变化,而...
开闭原则(Open-Closed Principle,简称OCP)是软件设计模式中的一个基本原则,由艾兹格·迪米特里斯·伯纳斯-李提出。这个原则指出,软件实体(类、模块、函数等)应当对扩展开放,对修改关闭。换句话说,当软件...
在软件开发中,开闭原则是面向对象设计中最基础的设计原则之一,它指导我们如何建立稳定灵活的系统。开闭原则定义:一个软件实体如类、模块和函数应该对扩展开放,对修改关闭。然而,开闭原则仅仅告诉我们对扩展开放...
设计原则如单一职责原则(SRP)、开闭原则(OCP)等在此阶段会得到详细介绍。 第2章“数据流图设计”专注于数据流图(DFD)这一重要的建模工具。DFD用于描绘系统的数据流程,帮助理解业务逻辑和信息处理过程。学习...
- **开闭原则(Open-Closed Principle, OCP)**:一个模块应该对扩展开放,对修改关闭。这意味着当需要添加新功能时,应通过扩展而不是修改现有代码来实现。 2. **里氏代换原则(Liskov Substitution Principle, ...
而设计模式则是在软件设计中反复出现的、解决常见问题的有效解决方案,它们是经验丰富的开发者们智慧的结晶。 UML作为建模语言,提供了多种图表类型,包括用例图、类图、序列图、状态图、活动图等,它们分别对应...
软件设计的七大原则是软件设计的精髓所在,这七大原则分别是开闭原则、里氏代换原则、依赖倒置原则、接口隔离原则、合成/聚合复用原则、迪米特法则和抽象类原则。 一、 开闭原则(OCP) 开闭原则是指一个软件实体...
### 软件设计原则与模式深度解析及案例分析 #### 一、软件设计原则的重要性与深度解析 软件设计原则是构建高质量软件的基础。遵循良好的设计原则可以帮助开发者编写出易于维护、扩展性强、且具有良好性能的软件...
总结来说,软件设计原则在嵌入式领域的应用,要求开发者在设计和实现时考虑系统的可维护性、可扩展性和复用性。通过合理应用开闭原则、单一职责原则、模块化、依赖倒置原则、设计模式以及代码结构的继承和抽象,可以...
其中包括SRP(单一职责原则)、OCP(开闭原则)、LSP(里氏替换原则)、ISP(接口分离原则)、DIP(依赖倒置原则)、CRP(组合/聚合复用原则)和PLK(最小知识原则)。 一、SRP(Single Responsibility Principle)...
一、 开闭原则(OCP) 开闭原则是指一个软件实体应当对扩展开放,对修改关闭。客户的需求是不稳定的,通过扩展已有的软件系统而不是通过修改软件系统来满足客户的需求,这样的软件系统就满足开-闭原则,即软件系统...
2. 开闭原则(Open/Closed Principle, OCP):软件实体应当对扩展开放,对修改关闭。这意味着软件系统应该能够在不修改现有代码的基础上进行功能的扩展。 3. 里氏替换原则(Liskov Substitution Principle, LSP):...
"开闭原则"是面向对象设计中的一个核心原则,由艾尔伯特·勒菲在1988年的《对象导向软件构造》一书中提出。它规定软件模块应该对扩展开放,但对修改关闭。这意味着在不改变原有代码的基础上,可以通过添加新的代码来...
总的来说,Java设计模式中的开闭原则是一个指导软件设计的重要原则,它鼓励我们设计出易于扩展、难以修改的系统。通过合理地使用抽象和实现分离,我们可以构建出更加健壮、适应性强的软件架构,从而降低维护成本,...
Closed Principle,简称OCP)是面向对象设计中的一个核心原则,它由Bertrand Meyer在1988年提出,并被收录在SOLID(单一职责原则、开闭原则、里氏替换原则、接口隔离原则、依赖倒置原则)这五大设计原则之中。...
开闭原则(OCP) - **定义**:“软件实体应当对扩展开放,对修改关闭。”这意味着可以在不修改现有代码的情况下添加新的功能。 - **实现方法**:通过抽象来实现开闭原则。设计抽象接口或基类,规定所有具体实现必须...