Phi*_*l H 19 language-agnostic oop encapsulation functional-programming semantics
面向对象设计(OOD)结合了数据及其方法.据我所知,这实现了两件好事:它提供了封装(所以我不关心那里有什么数据,只关心我如何得到我想要的值)和语义(它将数据与名称联系起来,以及它方法始终如一地使用数据.
那么OOD的优势在哪里呢?相反,函数式编程将丰富性归因于动词而不是名词,因此封装和语义都是由方法而不是数据结构提供的.
我使用的是一个处于功能末端的系统,并且不断地用于OO的语义和封装.但我可以看到OO的封装可能成为对象灵活扩展的障碍.所以目前,我可以看到语义更强大.
或封装是所有有价值代码的关键?
编辑:我的意思是OO提供的封装类型.changeColor(door,blue)成为door.changeColor(blue).
小智 30
您似乎使用了一个相当狭窄的"封装"定义.我是否正确地假定您将封装定义为"将数据与方法结合?"
如果我错了,请忽略这篇文章的其余部分.
封装不是一个松散的术语; 事实上,它是由国际标准化组织定义的.ISO的开放分布式处理参考模型 - 定义了以下五个概念:
实体:任何感兴趣的具体或抽象事物.
对象:实体的模型.对象的特征在于其行为,并且双重地由其状态来表征.
(对象的)行为:具有一组约束的动作集合,它们何时可能发生.
接口:对象行为的抽象,包括该对象的交互子集以及可能发生的一组约束.
封装:只能通过对象支持的接口上的交互来访问对象中包含的信息的属性.
我们可以进一步提出一个不言而喻的建议:由于某些信息可以通过这些接口访问,因此某些信息必须隐藏在对象内且无法访问.这些信息展示的属性被称为信息隐藏,Parnas通过论证模块应该被设计为隐藏可能发生变化的困难决策和决策来定义,参见一个伟大的计算文件:
http://www.cs.umd.edu/class/spring2003/cmsc838p/Design/criteria.pdf
重要的是要注意,不仅是信息隐藏的数据:它是与对象相关联的行为的一些子集,难以或可能发生变化.
在您的帖子中,您似乎在说OO封装和函数式编程之间的区别源于数据管理,但至少根据ISO和Parnas,数据管理不是封装的关键.所以我不明白为什么函数式编程中的封装需要与OO中的封装有任何不同.
此外,你在帖子中提到函数式编程提供了封装,"......通过方法而不是数据结构."我认为,这是规模的差异,而不是绝对的差异.如果我使用"对象"这个词,而不是"数据结构",(再次,如果我误解,请告诉我),那么你似乎通过对象和函数编程的方法封装在OO的封装中找到了重要性.
然而,根据上面的ISO定义,对象是我想要建模的任何东西.因此,类可以封装在包中,只要这些类中的一些对包的接口(即包的公共类)有贡献,而有些类是信息隐藏的(包中的私有类).
出于同样的原因,方法被封装在一个类中 - 一些方法是公共的,一些是私有的.你甚至可以把它降低一点,并说McCabian顺序的代码序列被封装在方法中.每个都形成封装在封装区域内的节点图; 并且所有这些图形形成图形堆栈.因此,函数式编程可以很好地封装在函数/文件级别,但这与OO的方法/类图没有什么不同,并且与OO的类/包图基本上没有区别.
另外,请注意Parnas上面使用的单词:change.信息隐藏涉及潜在事件,例如将来更改困难的设计决策.你问OO的力量在哪里; 封装肯定是OO的强项,但问题就变成了"封装的力量在哪里?"而答案是一个响亮的清晰度:变革管理.特别是,封装减少了最大的潜在变化负担.
"潜在耦合"的概念在这里很有用.
"耦合"本身被定义为"从一个模块到另一个模块的连接建立的关联强度的度量",在计算机的另一篇优秀论文中:
http://www.research.ibm.com/journal/sj/382/stevens.pdf
正如报纸所说的那样,用最好的语言来说,"最小化模块之间的连接也可以最大限度地减少变化和错误传播到系统其他部分的路径,从而消除灾难性的"涟漪"效应,其中一部分的变化导致另一方面的错误,需要在其他地方进行其他更改,从而产生新的错误等."
然而,如这里所定义的,有两个限制可以很容易地解除.首先,耦合不会测量模块内连接,并且这些模块内连接可以产生与模块间连接一样多的"纹波"效应(本文确定,"Cohesion"),以关联模块内部元素,但这不是根据元素之间的连接(即对标签或地址的引用)定义的,而是使用它来定义耦合.其次,任何计算机程序的耦合都是给定的,因为模块是连接的; 在耦合的定义中几乎没有范围来管理Parnas所说的潜在变化.
这些问题在某种程度上都与潜在耦合的概念一起得到解决:在程序的所有元素之间可形成的最大可能连接数.例如,在Java中,包中的包私有(默认访问器)的类不能在其上形成连接(即,没有外部类可以依赖它,尽管有反射),但包中的公共类可以有依赖性.即使目前没有其他类依赖于它,这个公共类也会对潜在的耦合做出贡献 - 当设计发生变化时,类可能会依赖于它.
要了解封装的强度,请考虑负担原则.负担原则有两种形式.
强形式表明,转换实体集合的负担是转换实体数量的函数.弱形式表明,转换实体集合的最大潜在负担是转换的最大潜在实体数量的函数.
创建或修改任何软件系统的负担是创建或修改的类的数量的函数(这里我们使用"类",假设一个OO系统,并且关注类/包级别的封装;我们同样可以关注函数式编程的功能/文件级别.(请注意,"负担"是现代软件开发通常是成本,或时间,或两者兼而有之.)依赖于特定修改类的类比不依赖于修改类的类具有更高的受影响概率. .
修改后的类可能施加的最大潜在负担是所有依赖于它的类的影响.
因此,减少对已修改类的依赖性可降低其更新将影响其他类的可能性,从而减少该类可能施加的最大潜在负担.(这只不过是对"结构化设计"论文的重新陈述.)
因此,减少系统中所有类之间的最大可能依赖性数量可以降低对特定类的影响将导致更新其他类的可能性,从而减少所有更新的最大潜在负担.
因此,通过减少所有类之间的最大可能依赖性数量来减少封装,从而减轻了负担原则的弱形式.这就是"封装理论"所涵盖的,它试图在数学上证明这种断言,使用潜在的耦合作为构造程序的逻辑手段.
但请注意,当你问:"封装是否是所有有价值代码的关键?"答案肯定是:不.所有有价值的代码都没有单一的密钥.在某些情况下,封装只是一种有助于提高代码质量的工具,因此它可能变得"值得".
你还写道,"...封装可能成为对象灵活扩展的障碍."是的,它当然可以:它确实是一个障碍,不能扩展难以或可能改变的对象的设计决策.然而,这并不是一件坏事.另一种方法是将所有类别公开,并使程序表达其最大潜在耦合; 但是,负担原则的薄弱形式表明,更新将变得越来越昂贵; 这些是衡量延伸障碍的成本.
最后,您在封装和语义之间进行了有趣的比较,并且在您看来,OO的语义是其更大的优势.我也不是语义学家(我甚至不知道拉姆齐先生在他的评论中提到这个词之前就存在这样一个词)但我认为你的意思是"语义学",意思是"意义,或者解释一个词的含义,"而且基本上一个带有aof,woof()方法的类应该被称为Dog.
这种语义确实有很大的力量.
对我来说很奇怪的是,你会将语义与封装相提并论,并寻找胜利者; 我怀疑你会找到一个.
在我看来,有两种推动封装的力量:语义和逻辑.
语义封装仅仅意味着基于封装的节点(使用通用术语)的含义进行封装.所以如果我告诉你我有两个包,一个叫'动物',一个叫'矿物',然后给你三个类Dog,Cat和Goat并询问这些类应该封装哪些包,然后给出没有其他信息,你会完全正确地声称系统的语义会暗示这三个类被封装在"动物"包中,而不是"矿物".
然而,封装的另一个动机是逻辑,特别是上面提到的潜在耦合的研究.封装理论实际上提供了应该用于封装多个类的封装数量的等式,以便最小化潜在的耦合.
对我来说,封装作为一个整体是这种语义和逻辑方法之间的权衡:如果这使程序在语义上更容易理解,我将允许我的程序的潜在耦合超过最小值; 但是巨大而浪费的潜在耦合程度将警告我的程序需要重新构建,无论它在语义上多么明显.
(如果好拉姆齐先生还在阅读,那么你或你的语义学家朋友能否给我一个更好的词汇,"语义学",我在这里使用的阶段?用一个更合适的术语会更好.)
此致,Ed.
封装和由此产生的抽象显然是OO的主要优势."事物"断言可以对它们调用什么"行动",因此名词比动词具有更高的语义重要性.
最终,如果没有一定程度的封装,很难设想以一致且可维护的形式设计复杂系统.
作为一个Lisp程序员,他的对象系统可以说没有提供这些,我说:以上都不是.
jwz:"伪Smalltalk对象模型丢失,并且通用函数(适当地受无外部覆盖规则约束)获胜".
我认为你和其他人在这里列出的理想属性(封装,模块化等)并不像你想象的那样在OO中固有.它们通常与Java风格的OO一起提供,但不仅仅是它的结果.
| 归档时间: |
|
| 查看次数: |
2049 次 |
| 最近记录: |