您的位置:首页 > 其它

通过有趣的对话来学习面向对象的设计原则

2017-06-28 11:48 459 查看


我如何向我的妻子解释OOD

 
通过有趣的对话来学习面向对象的设计原则。


介绍

我的妻子Farhana希望恢复自己的软件开发人员的职业生涯(她作为一名软件开发人员开始了自己的职业生涯,但由于我们的第一个孩子的出生而无法进行),而且这些天,我正在帮助她学习面向对象设计因为我在软件设计和开发方面有一些经验。
自从我在软件开发的早期,我一直认为,无论技术问题如何困难,如果从现实生活的角度进行解释并以对话的方式进行讨论,总是会变得更加容易。当我们在面向对象设计上进行了一些富有成效的对话时,我认为我可以分享它,因为有人可能会发现它是一种有趣的学习OOD的方法。
以下是我们的OOD对话如何发生:


主题:介绍OOD

Shubho:亲爱的,我们开始学习面向对象设计。你知道面向对象的原则吗?
Farhana:你的意思是封装,继承和多态吗?是的,我知道原则。
Shubho:好的,我希望你已经知道如何使用类和对象。让我们今天学习面向对象设计。
Farhana:一秒钟。面向对象的原理是否不足以进行面向对象编程?我的意思是,我可以定义类和封装属性和方法。我也可以根据他们的关系定义一个类层次结构。那么剩下的是什么?
Shubho:好问题 面向对象的原理和面向对象的设计实际上是两个不同的东西。让我给你一个真实的例子来帮助你理解。
当你小时候,你首先学习字母,对吧?
Farhana:是的
Shubho:好的。你也学习了单词,以及如何组合字母来表达有意义的词语。与此同时,你学到了一些基本的语法来组合句子。例如,你必须保持时态,你不得不使用介词,连词和其他人来正确地创建语法正确的句子。说一句话如下:

隐藏   复制代码
"I" (pronoun) "want" (Verb) "to" (Preposition) "learn" (Verb) "OOD" (Noun)

你看,你是按某种顺序组合的,你也选择正确的单词,最终得到一个含义的句子。
Farhana:好的,那是什么意思?
Shubho:这类似于面向对象的原则。OOP说出了面向对象编程的基本原理和核心思想。在这里,OOP可以与基本的英语语法进行比较,其中基本语法教你如何使用单词构造有意义和正确的句子,OOP教你如何构建类,封装其中的属性和方法,并且还可以在他们在你的代码中使用它们。
Farhana:Hm ..我得到了点。那么OOD在哪里适合?
Shubho:你会很快得到你的答案。现在,假设你需要在一些话题上写文章和论文。您也可能希望为您拥有专业知识的不同科目撰写书籍。知道如何构造句子不足以编写好的文章/文章或书籍,对吧?你需要写很多,需要学习用好的方式来解释事情,让读者能够轻易地理解你想说的话。
Farhana:似乎有趣...继续。
Shubho:现在,如果你想写一本关于特定主题的书(比如说面向对象的学习设计),你必须知道如何把这个主题划分成较小的主题。您还需要编写这些主题的章节,您需要在章节中编写前言,介绍,解释,示例和其他许多段落。您需要设计整本书,并学习一些写作技巧的最佳做法,以便读者可以轻松了解您要解释的内容。这是关于更大的图片。
在软件开发中,OOD解决了更大的问题。您需要以您的类和代码模块化,可重复使用和灵活的方式设计软件,并且有一些良好的指导方针,以便您不必重新创建轮子。有一些设计原则,您可以应用于设计您的类和对象。说得通?
Farhana:嗯..有最初的想法,但需要学习更多。
Shubho:别担心,你会很快学习。只是让我们的讨论进行。


主题:为什么是OOD?

Shubho:这是一个非常重要的问题。当我们可以快速创建一些课程并完成开发和交付时,为什么要关心面向对象设计?还不够吗
Farhana:是的,我以前不太了解OOD,而且还能够开发和交付项目。那么什么大事呢?
Shubho:好的,让我给你一个经典的报价:

“如果两者都冻结,步行上水和从规范开发软件很容易。”
爱德华· 贝拉德

Farhana:你的意思是软件开发规范不断变化?
Shubho:完全正确!软件的普遍真理是“你的软件一定会改变”。为什么?
因为,您的软件解决了现实生活中的商业问题和现实生活中的业务流程的演变和变化。
你的软件做的是今天应该做的,做得很好。但是,您的软件是否足以支持“更改”?如果没有,您没有精心设计的软件。
Farhana:好的,请解释“精心设计的软件”先生!
Shubho:“精心设计的软件可以轻松调整变更,可以扩展,可重复使用。”
并且,应用一个很好的“面向对象设计”是实现这样一个智能设计的关键。现在,你什么时候可以声称你在代码中应用了好的OOD?
Farhana:这也是我的问题。
Shubho:你正在做面向对象设计,如果你的代码是:
当然,面向对象。
可重复使用。
可以用最小的努力改变。
可以扩展而不改变现有的代码。
Farhana:和..?
Shubho:我们并不孤单 许多人已经提出了很多想法,并在这个问题上付出了很多的努力,他们试图实现良好的面向对象设计,并确定了面向对象设计的一些基本原则(一些基本的灵感,你可以用来布局面向对象的设计)。他们还确定了一些适用于常见情景(基于基本原则)的常见设计模式。
Farhana:你能命名吗?
Shubho:当然可以。有许多设计原则,但在基本层面上,有五个原则被简写为SOLID原则(感谢Bob叔叔,伟大的OOD导师)。

隐藏   复制代码
S = Single Responsibility Principle
O = Opened Closed Principle 
L = Liscov Substitution Principle
I = Interface Segregation Principle
D = Dependency Inversion Principle

在下面的讨论中,我们将尝试详细了解每一个。


主题:单一责任原则

Shubho:让我先来看你的海报。我们应该感谢制作海报的人,这些真的很有趣。



单一责任原则海报
它说,“只是因为您可以在单个设备中实现所有功能,您不应该”。为什么?因为从长远来看,它为您增加了很多可管理性问题。
让我以面向对象的方式告诉你原则。
“ 课堂改变不应该有一个以上的原因。 ”
或者说,“一班应该有一个责任”。
Farhana:你能解释一下吗
Shubho:当然,这个原则说,如果你有一个班有不止一个理由要改变(或有一个以上的整体责任),那么你需要根据自己的责任将班分成多个班级。
Farhana:嗯...这是否意味着我不能在单一类中有多种方法?
Shubho:没有。相反,您一定可以在单个类中使用多种方法。问题是,他们必须达到一个目的。现在,为什么分裂是重要的?
这很重要,因为:
每个责任都是变革的轴心。
如果课程有多个责任,代码就会变得复杂。
Farhana:可以请举个例子吗?
Shubho:当然,看看下面的层次结构。其实这个例子来自鲍伯叔叔,所以再次感谢他。



班级层级显示违反SRP原则
在这里,
Rectangle
该类执行以下操作:
它计算矩形区域的值。
它在UI中呈现矩形。
而且,两个应用程序正在使用这个
Rectangle
类:
计算几何应用程序使用此类来计算面积
图形应用程序使用该类在UI中绘制一个矩形
这违反SRP(单一责任原则)!
Farhana:怎么样?
Shubho:你看,
Rectangle
课堂其实是两个不同的事情。它是在一种方法中计算面积,并且在另一种方法中返回矩形的GUI表示。这会导致一些有趣的问题:
我们必须将GUI包含在计算几何应用程序中。在部署几何应用程序时,我们必须包括GUI库。
Rectangle
图形应用程序的类更改可能导致计算几何应用程序的更改,构建和测试,反之亦然。
Farhana:变得有趣 所以我想我们应该根据责任分类,对吧?
Shubho:完全正确 你能预测我们应该做什么吗?
Farhana:当然可以试试看。以下是我们可能需要做的:
将职责分为两类,如:
Rectangle
:这个类应该定义
area()
方法。
RectangleUI
:这个类应该继承
Rectangle
类并定义
Draw()
方法。
Shubho:完美 在这种情况下,
Rectangle
该类将被计算几何应用程序使用,
RectangleUI
该类将由图形应用程序使用。我们甚至可以将这些类别分成两个单独的DLL,这将使我们不要碰到另一个DLL,以防需要在其中实现更改。
Farhana:谢谢,我觉得我理解SRP。有一件事,SRP似乎是将事情分解成分子部分的想法,使其成为可重用的,可以集中管理的。那么,我们也不应该在方法层面应用SRP?我的意思是说,我们可能编写的方法有多行代码来做多件事情。这些方法可能违反SRP,对吧?
Shubho:你说得对。你应该分解你的方法,以便每个方法都做一个特别的工作。这将允许您重新使用方法,如果需要更改,您可以通过修改最少的代码来进行更改。


主题:开放原则

Shubho:这里是开放原则的海报:



图:打开封闭原则海报
如果我需要以面向设计的方式解释,那将如下:
“ 软件实体(类,模块,函数,等等)应该对扩展开放,但对修改关闭。 ”
在最基本的层次上,这意味着你应该能够扩展一个类的行为而不进行修改。这就像我应该能穿上一件衣服,而不是改变我的身体,哈哈。
Farhana:有趣的 你可以通过放任何你想要的衣服改变你的外观,你不必改变你的身体。所以你打开扩展,对吧?
Shubho:是的 在OOD中,对于扩展开放意味着可以扩展模块/类的行为,并且可以使模块以新的和不同的方式按照需求改变,或者满足新应用的需求。
Farhana:你的身体被关闭以进行修改。我喜欢这个例子。因此,当需要扩展时,不应修改核心类或模块的源代码。你可以用一些例子来解释一下吗
Shubho:好的,请看下面的例子。这不支持“开放式”原则:



类层次显示违反开放原则
你看,客户端和服务器类都是具体的。所以,如果由于任何原因,服务器实现被改变,客户端也需要改变。
Farhana:有意义 如果将浏览器实现为与特定服务器(例如IIS)紧密耦合,则如果由于某种原因将服务器替换为另一个服务器(例如,Apache),则浏览器也需要更改或替换。那真是太可怕了!
Shubho:正确 所以以下是正确的设计:



班级层次显示开放封闭原则
在此示例中,添加了一个Abstract Server类,客户机持有对抽象类的引用,而Concrete Server类实现了Abstract Server类。因此,如果由于任何原因,服务器实现被更改,客户端不太可能需要任何更改。
这里的Abstract Server类被关闭以进行修改,这里的具体类实现是可以扩展的。
Farhana:据了解,抽象是关键,对吧?
Shubho:是的,基本上你抽象出系统核心概念的东西,如果你的抽象很好,最有可能的是,当功能扩展时,它不需要改变(比如服务器是一个抽象的概念)。而且,您可以尽可能地定义实现中的抽象事物(比如说IISServer实现Server)和代码与抽象(Server)。这将允许您扩展抽象的东西并定义一个新的实现(比如说ApacheServer),而不会改变客户端代码。


主题:Liskov的替代原则

Shubho:“Liskov的替代原则”这个名字听起来很重,但这个想法是非常基本的。看看这个有趣的海报:



Liskov替代原则海报
原则说:
“ 子类型必须为替代他们的基本类型。 ”
或者,如果不同:
“使用对基类的引用的函数必须能够使用派生类的对象而不知道它。
Farhana:对不起,听起来很混乱。我以为这是OOP的基本规则。这是多态性吧?为什么在这个问题上需要面向对象的原则?
Shubho:好问题 这是你的答案:
在基本的面向对象原则中,“继承”通常被描述为“是一个”关系。如果“开发人员”是“SoftwareProfessional”,那么“开发者”类应该继承“SoftwareProfessional”类。这样的“关系”在课堂设计中是非常重要的,但很容易被遗弃,最终导致错误的设计,遗传不好。
“Liskov的替代原则”只是确保继承正确使用的一种方式。
Farhana:我明白了 有趣。
Shubho:是的,亲爱的,确实。我们来看一个例子:



类层次结构显示了Liskov替代原则的一个例子
在这里,
KingFisher
类扩展了
Bird
基类,因此继承了该
Fly()
方法,这是非常好的。
现在来看下面的例子:



更正了Liskov替代原则的阶级层次
鸵鸟是鸟(绝对是!),因此它继承了Bird类。现在可以飞吗?没有!在这里,设计违反了LSP。
所以,即使在现实世界中,这似乎是自然的,在课堂设计中,鸵鸟不应该继承Bird类,应该有一个单独的类,不能真正飞翔的鸟,Ostrich应该继承它。
Farhana:好的,明白了 所以,让我试着指出为什么LSP是如此重要:
如果不保持LSP,则类层次结构将会变得混乱,如果子类实例作为参数传递给方法,则可能会发生奇怪的行为。
如果没有维护LSP,基类的单元测试永远不会成功。
我对吗?
Shubho:你是对的 您可以设计对象并应用LSP作为验证工具来测试层次结构是否继承正确完成。


主题:接口隔离原理

Shubho:今天我们将学习“界面隔离原理”。这是海报:



界面隔离原则海报
Farhana:这是什么意思?
Shubho:这意味着:
“ 客户不应该被迫依赖于他们不使用的接口。 ”
Farhana:请解释
Shubho:当然,这是你的解释:
假设你想购买电视,你有两个选择。一个有许多开关和按钮,其中大多数看起来很混乱,似乎不需要你。另外有几个开关和按钮,这似乎是熟悉和合乎逻辑的。鉴于两台电视提供的功能大致相同,您可以选择哪一个?
Farhana:显然,第二个具有较少的开关和按钮。
Shubho:是的,但为什么?
Farhana:因为我不需要开关和按钮,看起来令人困惑和不必要。
Shubho:正确 同样,假设您有一些类,并且使用接口公开类的功能,以便外部世界可以知道类的可用功能,并且可以针对接口完成客户端代码。现在,如果接口太大,并且有太多的暴露方法,那对外界来说似乎是混乱的。此外,具有太多方法的接口不太可重复使用,并且具有额外无用方法的这种“胖接口”导致类之间的增加的耦合。
这也导致另一个问题。如果一个类想要实现接口,那么它必须实现所有的方法,其中一些方法可能根本不需要。因此,这样做也会引起不必要的复杂性,并降低系统的可维护性或稳健性。
界面隔离原则确保开发接口,以使每个人都有自己的责任,因此它们是特定的,易于理解的和可重复使用的。
Farhana:我明白了 你的意思是接口应该只包含必要的方法而不是其他任何东西?
Shubho:完全正确 我们来看一个例子。
以下界面是“Fat界面”,它违反了界面隔离原则:



接口违反接口原则的接口示例
请注意,该
IBird
界面与
Fly()
行为一起定义了许多鸟类行为。现在,如果一个Bird类(例如鸵鸟)实现了这个接口,它必须
Fly()
不必要地执行这个行为(鸵鸟不飞)。
Farhana:没错。那么这个接口必须拆分?
Shubho:是的 “Fat
Interface”应该分解成两个不同的接口,
IBird
并且
IFlyingBird
在哪里
IFlyingBird
继承
IBird




界面隔离原理示例中接口的正确版本
如果有一只不能飞的鸟(鸵鸟),那么它将实现
IBird
接口。如果有一只可以飞的鸟(比如说KingFisher),那么它会实现
IFlyingBird
接口。
Farhana:所以,如果我用很多开关和按钮的电视机回到这个例子,那个电视机的制造商必须有这个电视机的蓝图,那里的电视机和按钮都包含在这个计划中。每当他们想要创建一个新的电视模型,如果他们需要重新使用这个蓝图,他们将需要创建尽可能多的开关和按钮,包括在计划中。这不允许他们重新使用计划,对吧?
Shubho:对。
Farhana:如果他们真的想重新使用他们的计划,他们应该把电视的蓝图分成较小的部分,以便每当创建任何新的电视时都可以重新使用这个计划。
Shubho:你有这个想法。


主题:依赖性反转原则

Shubho:这是SOLID原则中的最后一个原则。这是海报:



依赖性反转原则海报
它说..
“ 高级别模块不应该依赖于低级模块,而应该取决于抽象。 ”
Shubho:让我们考虑一个真实世界的例子来理解它。你的车是由发动机,轮子,空调等物体组成的,对吗?
Farhana:是的,当然。
Shubho:好的,这些东西都不是刚刚在一个单位内建成的; 相反,这些都是“可插拔的”,所以当发动机或车轮有问题时,您可以修理它(不修理其他东西),甚至可以更换它。
在更换时,您只需确保发动机/车轮符合汽车的设计(例如,汽车将接受任何1500 CC发动机,并将运行在任何18英寸的车轮上)。
此外,鉴于制造商(例如,丰田)是相同的,事实上,汽车可能允许您放置2000 CC发动机代替1500 CC。
现在,如果你的车的不同部分没有建立在这样一个“可插拔的性质”呢?
Farhana:那太可怕了!因为在这种情况下,如果你的车的发动机出现故障,你将不得不修理整车或者购买新车!
Shubho:是的 现在,“可插拔性”如何实现?
Farhana:“抽象”是关键,对吧?
Shubho:是的 在现实世界中,汽车是较高级别的模块/实体,它取决于较低级别的模块/实体,如发动机或车轮。
汽车不是直接依赖于发动机或车轮,而是取决于发动机或车轮的某些规格的抽象,因此如果发动机或车轮符合抽象,则可以将车辆与汽车组合起来。
我们来看下面的类图:



依赖性反转原则类层次结构
Shubho:在上面的
Car
类中,注意有两个属性,它们都是抽象类型(Interface),而不是具体类型。
引擎和车轮是可插拔的,因为汽车将接受实现声明的接口的任何对象,并且不需要在
Car
类中进行任何更改。
Farhana:所以,如果代码中没有实现依赖性反转,我们冒着:
损害使用较低级别类的较高级别的代码。
需要太多时间和精力来改变较低级别的代码。
生成不太可重用的代码。
Shubho:你有完美的亲爱的!


概要

Shubho:除了SOLID原理之外,还有许多面向对象的原则。有些是:
“继承继承的组合”:这就是说有利于构成遗产。
“最不了解的原则”:这就是说,“班级知道的越少越好”。
“共同关闭原则”:这就是说“相关类应该包装在一起”。
“稳定抽象原则”:这就是说,“一个阶级越稳定,就越需要抽象类”。
Farhana:我不应该学习这些原则吗?
Shubho:是的,当然。你有整个万维网来学习。只是谷歌在这些原则上试图理解。当然,请不要犹豫,问我是否需要帮助。
Farhana:我听说有许多基于这些设计原则的设计模式。
Shubho:你是对的 设计模式只不过是一般常见的常见设计建议。这些主要受到面向对象设计原则的启发。您可以将设计模式视为“框架”,将OOD原则视为“规格”。
Farhana:那么下面我要去学习设计模式吗?
Shubho:是亲爱的
Farhana:那会退出,对吧?
Shubho:是的,那真的会退出。

转载自[https://www.codeproject.com/Articles/93369/How-I-explained-OOD-to-my-wife]

下片链接 https://www.codeproject.com/Articles/98598/How-I-explained-Design-Patterns-to-my-wife-Part-1
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: