如何使私有成员对象封装?

cod*_*eno 6 erlang f# scala clojure

在Scala中,通过键入,private[this]我们可以使私有成员只能由该类的特定对象访问,而同一个类的另一个对象无法访问它.如果可能的话,我们怎样才能在其他语言中实现这一点......尤其是F#,Erlang和Clojure?

Jör*_*tag 7

您所询问的基本上是面向对象的数据抽象抽象数据类型的数据抽象(ADT,不要与代数数据类型混淆,后者也经常缩写为"ADT").(见的了解数据抽象,再访威廉·R·库克,他简体议案,"对象"和"面向对象"的现代定义,和面向对象编程对战抽象数据类型.)

相同抽象数据类型的两个不同实例可以检查彼此的表示(但不是其他抽象数据类型的实例的表示),而对象永远不能检查另一个对象的表示,即使该对象是相同类型的实例.Cook将此属性识别为面向对象数据抽象(实际上是面向对象)的基本和定义特征,并将其称为自我认知(Self-Knowledge).我更喜欢Xenoagnosis(Foreign-Not-Knowledge)一词,由Glenn Vanderburg,Rick de Natale或已故的Jim Weirich,IIRC应用,因为它强调了两种方法之间的差异,即对象无法了解其他方法对象.

在Scala中,正如您所注意到的,可以通过private[this]访问修饰符实现面向对象的数据抽象.

class TestPrivate {
  private       val notReallyPrivate = 42
  private[this] val privateIMeanIt   = 23

  def blowUp(other: TestPrivate) = {
    other.notReallyPrivate
    other.privateIMeanIt
  }
}
// error: value privateIMeanIt is not a member of TestPrivate
Run Code Online (Sandbox Code Playgroud)

在Erlang中,与Object相当的是一个Process,而Processes完全由语言语义封装(它们甚至有自己的垃圾收集内存).毕竟,它们甚至可以生活在不同大陆的不同机器上,因此暴露表示只是不切实际.您向流程发送消息,并且流程在决定如何处理消息以及如何响应消息时完全自主.一切都是private[this],基本上.

在Clojure中,可以通过Closures实现面向对象的数据抽象.(对于几乎所有带闭包和高阶子程序的语言都是如此,例如你也可以在Erlang中使用函数作为对象而不是进程.)想想ECMAScript:尽管它容易混淆地有一个叫做"object"的语言结构, ECMAScript对象实际上是使用函数实现的.你可以用同样的方式在Clojure中实现它们.面向对象的数据抽象形式也称为过程数据抽象,因为它不依赖于类型,而是依赖于将数据隐藏在过程接口(或功能接口)之后,如果你想要的话,它毕竟是可变性和副作用与OO正交).Cook(半开玩笑地)认为,因为λ演算只有函数,所有抽象都是函数式的,因此λ演算是第一个,最古老,最纯粹的OO语言 - 显然这意味着OO数据抽象必须在语言中紧密基于λ演算,如Lisp族.(历史轶事:Scheme最初是为了研究OO和Actors而设计的,他们只是在实现过程中注意到,用于消息发送和函数调用的解释器的代码路径是相同的.)

在Java或C♯等语言中,使用Type System和Programmer Discipline实现了Object-Orientation,只使用interfaces作为Types.interfaces无法描述表示,因此,只要您确保(通过程序员规则,编码样式,代码评论,可能是静态分析工具)只使用interfaces作为类型(每个局部变量,字段,方法参数,方法返回值) ,转换操作符,instanceof检查和泛型类型参数必须始终为a interface)和classes 仅用作工厂(允许出现类名的唯一位置直接位于new关键字旁边),然后您已实现面向对象的数据抽象.(还有一些其他注意事项,最重要的是你不能使用Reference Equality.)

interface ITestPrivate {
  default int thisIsPublic() { return 0; }

  default void blowUp1(ITestPrivate other) {
    other.thisIsPublic();
    other.privateIMeanIt();
  }
}

class TestPrivate implements ITestPrivate {
  private int privateIMeanIt() { return 23; }

  void blowUp2(TestPrivate other1, ITestPrivate other2) {
    other1.notReallyPrivate(); // works
    other2.notReallyPrivate(); // doesn't
  }
}
Run Code Online (Sandbox Code Playgroud)

在F♯中也应该这样做,因为F♯也支持interfaces.