Oop Scala和封装?
自从我开始研究OOP以来,封装一直是我的疑问所在。在99%的情况下,getter和setter看起来像是一个大谎言:如果setter更改了私有字段的引用,那么getter返回对可变对象的引用又有什么关系呢?当然,使用getter和setter模式(比如在实体上创建代理的Hibernate)有很多事情可以让生活变得更轻松。在Scala中有一种解决方案:不要对自己撒谎,如果你的字段是Oop Scala和封装?,oop,scala,encapsulation,Oop,Scala,Encapsulation,自从我开始研究OOP以来,封装一直是我的疑问所在。在99%的情况下,getter和setter看起来像是一个大谎言:如果setter更改了私有字段的引用,那么getter返回对可变对象的引用又有什么关系呢?当然,使用getter和setter模式(比如在实体上创建代理的Hibernate)有很多事情可以让生活变得更轻松。在Scala中有一种解决方案:不要对自己撒谎,如果你的字段是val,你就没有什么好担心的,只要把它公之于众就行了。 但这并不能解决方法的问题,我是否应该在Scala中声明私有方法
val
,你就没有什么好担心的,只要把它公之于众就行了。
但这并不能解决方法的问题,我是否应该在Scala中声明私有方法?为什么我要在Java中声明私有方法?大多数情况下,如果它是一个助手方法,并且我不想污染我的类名称空间,如果该方法更改了我们的内部状态。第二个问题不适用于Scala(主要是&希望如此),第一个问题可以通过适当的特性简单地解决。那么我什么时候想在Scala中声明私有方法呢?Scala中的封装约定是什么?如果您能帮我整理一下关于这个主题的想法,我将不胜感激。getter和setter(或accessor/mutator方法)用于封装数据,这通常被认为是OOP的原则之一
它们的存在使得对象的底层实现可以在不影响客户端代码的情况下进行更改,只要接口约定保持不变。这是一个旨在简化代码库维护和演化的原则 即使Scala也有封装,但它通过自动创建模仿属性名的访问器/变异器方法来避免显式使用get/set(JavaBean约定),从而支持统一访问原则(例如,对于公共
val name
属性,将生成相应的def name
公共访问器,对于var name
属性,还可以使用def name=
mutator方法)
例如,如果您定义
class Encapsulation(hidden: Any, val readable: Any, var settable: Any)
编译的.class
如下
C:\devel\scala_code\stackoverflow>javap -cp . Encapsulation
Compiled from "encapsulation.scala"
public class Encapsulation {
public java.lang.Object readable();
public java.lang.Object settable();
public void settable_$eq(java.lang.Object);
public Encapsulation(java.lang.Object, java.lang.Object, java.lang.Object)
}
Scala只是为了避免样板文件而设计的,它消除了定义此类方法的必要性
封装(或信息隐藏)不是为了支持Hibernate或其他框架而发明的。事实上,在Hibernate中,您应该能够直接注释属性字段,同时有效地打破封装
至于私有方法的有用性,这再次是一个好的设计原则,它导致了干代码(如果您有多个方法共享一段逻辑),更好地集中每个方法的责任,并支持相同部分的不同组合 这应该是您定义的每个方法的通用指南,并且只有一部分封装逻辑会出现在公共接口层,剩下的部分将作为私有(甚至本地)方法实现
在scala(与java一样)中,私有构造函数还允许您通过使用工厂方法来限制对象实例化的方式。封装不仅仅是getter/setter方法或public/private accessor修饰符的问题。这是java开发人员的一个常见误解,他们不得不花大量时间使用Hibernate(或类似的基于JavaBean规范的库) 在面向对象编程中,封装不仅指信息隐藏,还指将数据和方法(对该数据进行操作)捆绑在同一对象中 要实现良好的封装,必须明确区分您希望公开给公众的那些方法(所谓的公共接口)和对象的内部状态(必须符合其数据不变量) 在Scala中,有许多方法可以实现面向对象的加密。例如,我的首选方法之一是:
trait AnInterface {
def aMethod(): AType
}
object AnInterface {
def apply() = new AnHiddenImplementation()
private class AnHiddenImplementation {
var aVariable: AType = _
def aMethod(): AType = {
// operate on the internal aVariable
}
}
}
首先,定义trait(公共接口),以便立即明确客户端将看到什么。然后编写它的伴生对象,以提供一个工厂方法,该方法实例化默认的具体实现。如果在伴生对象中定义private,则该实现可以对客户端完全隐藏
正如您所看到的,Scala代码比任何Java解决方案都要简洁得多许多字段实际上不应该有getter,而且扩展起来,即使在没有变异风险的情况下也不应该是公共的。如果我理解正确,您的意思是,如果我们有一个DAO,它包含一个
EntityManager
,其他人就不应该使用它。你是对的,但是应该有办法贴上“如果移除,保修无效”的标签,而不是在其周围贴一堵玻璃墙。使用特性似乎是一个很好的解决方案。我不确定你所说的“如果移除,保修无效”是什么意思贴纸。你能举个例子吗?我的意思是,任何人都不应该使用DAO持有的EntityManager
,如果他使用了,他就会停止正确的设计。这就是为什么它应该是私有的,这样除了DAO之外,没有对象可以访问它