私有嵌套 类 - 它们是合成所必需的吗?

Private nested classes - are they necessary for composition?

这是我幼稚的思考过程。如果有人指出任何差异,我将不胜感激。

我知道在 Java 中可以创建私有嵌套 classes。但是在 PHP(自称为 "OOL")中,这样的事情是不可能轻易实现的。

但是,可能会有这样的情况,我需要在 只有一个 其他 class.

中使用助手 class

这自然促使我考虑使用组合,我认为它应该真正解决此类问题,原因如下:

Wikipedia:

  • It is only called composite, if the objects it refers to are really its parts, i.e. have no independent existence.
  • Aggregation differs from ordinary composition in that it does not imply ownership. In composition, when the owning object is destroyed, so are the contained objects. In aggregation, this is not necessarily true.

因此,由于在组合中 组件 不应该在没有另一个 复合对象 的情况下存在,我假设基本上只有一个通过使用 private nested classes 实现此目的的方法,否则我将需要 Component class 可见,使其在其他地方也可以实例化,违反了 creation/destruction-of-components-within-the-composite-class rule.

现在我遇到 PHP 根本不可能创建嵌套 classes(或者可能有一些魔法),这可能会导致一个问题,为什么我们需要嵌套 class 有吗?

Compelling reasons for using nested classes include the following:

  • It is a way of logically grouping classes that are only used in one place: If a class is useful to only one other class, then it is logical to embed it in that class and keep the two together. Nesting such "helper classes" makes their package more streamlined.

  • It increases encapsulation: Consider two top-level classes, A and B, where B needs access to members of A that would otherwise be declared private. By hiding class B within class A, A's members can be declared private and B can access them. In addition, B itself can be hidden from the outside world.

  • It can lead to more readable and maintainable code: Nesting small classes within top-level classes places the code closer to where it is used.

所以在我看来,随着嵌套 classes 增加封装(并因此允许实现复合概念),应该始终可以在适当的 OOL 中创建嵌套 class。

我也查了OOP的定义,里面只提到支持封装、抽象、继承、多态等概念。

OOP

Encapsulation means that the internal representation of an object is generally hidden from view outside of the object’s definition.

Abstraction is the development of classes, objects, types in terms of their interfaces and functionality, instead of their implementation details. (e.g. instead or creating a single sequence of commands to work with a radius and points we would abstract a concept of a circle. So we define a class Circle and a its attributes/functions in such a way that it reflects this abstract concept.)

Inheritance is supposed to be the is-a relationship between abstractions (allowing for code reuse).

Polymorphism allows for overriding and overloading methods.

一个人问了一个问题 here 这实际上完全符合我对问题的理解,恕我直言,收到了相当不准确的答案,被告知真的很困惑,并提供了一个代码示例,而 IMO 不是适当的构图,因为这在 PHP 中是不可能的。此外,有人可能会争辩说合成与内部 classes 无关。

我是不是理解错了?

组合这样的概念是通用的,它们的实现可能因编程语言而异。

另一方面,我不会说包含[...]的组合的定义没有独立存在指的是是否可以从不同的范围创建实例。

没有独立存在是概念多于实际的规则。这意味着 wheel 永远不可能是 composition root 因为 root汽车。也就是说,车轮不能独立于汽车而存在

因此,结论是嵌套classes只是一个实现细节,与组合无关。请注意,对象并非在所有编程语言中都由 classes 创建,但组合和许多其他功能仍然是可能的。你会说对象组合在 JavaScript 中是不可能的吗?

var car = { manufacturer: "Ford", model: "Focus" };
// I can create the wheel after the car
var wheel = { color: "black" };
// but it'll be always tied to some car
car.wheel = wheel;

无论如何,几乎所有系统都实现了聚合,这是组合的一种形式。在 Software Engineering 查看 this Q&A

虽然 车轮 不作为 汽车 的一部分就毫无用处,但车轮仍然作为许多机械部件之一单独出售汽车是造出来的,所以轮子可以单独生活,但它只是一块没用。

OOP 中组合的通用定义

OP 过于关注并侧重于 UML 方面的组合的正式定义:组合、关联、直接关联、聚合...

顺便说一句,OOP中的术语组合有一个更简单的含义,经常被使用,例如,当讨论何时使用继承或何时避免继承时,我们谈论composition over inheritance. See for example this Q&A from 2010: What is composition as it relates to object oriented design? 基本上所有回答者都对组合的定义达成共识

归根结底,术语组合是创建对象图的方法:简单类型关联在一起以创建更复杂的类型。

因此,正如我已经在本答案的第一部分中解释的那样,嵌套 classes 只是一种编程语言实现细节,它们不是对于实现任何风格的组合都至关重要。

OP 在一些评论中说:

But conceptually in order to implement it properly as a composition, I'd prefer something like partial classes (as in C#) allowing me to separate code into multiple files but restricting the instantiability to the main class only. I know you don't agree with me, I have to express my view somehow.

这是一个错误的示例,因为 partial classes 只是一个语法糖,用于粘合定义相同 class 的多个文件,之后一切都是相同 class。

C# 有 嵌套 classes:

public class A
{
     public class B
     {
     }
}

但是你需要明白类型定义从概念的角度与对象没有任何关系因为面向对象的语言可能有也可能没有类型系统和 classes,但它可以支持组合及其所有风格。

在维基百科中,还有以下不使用私有嵌套 classes 的组合示例。

class University
{
  std::vector<Department> faculty; //this is composition
  std::vector<People*> people; //this is aggregation

  University()  // constructor
  {
    // Composition: Departments exist as long as the University exists
    faculty.push_back(Department("chemistry"));
    faculty.push_back(Department("physics"));
    faculty.push_back(Department("arts"));
  }
};

对于真正的组合,我们不必将整个 class 私有化,只要我们适当地处理部门实例即可,即我们需要确保所有部门在大学时实际被删除不复存在。

在 JavaScript 中实现不同组合的类似方法如下:

/*this is a component's "class"*/
function Text(txt){
   this.txt = txt;
}

/*this is a composite's "class"*/
function Hello(begining){
   /*public object*/
   this.begining = begining;

   /*this is like making an instance from a nested function which is a composite*/
   var Middle = new (function Middle(txt){
       this.txt = txt;
   })(" - ");

   /*private object - also a composite, even though it's made of the public class Text*/
   var Ending = new Text("that's all.");

   /*The use of the private property Ending*/
   this.Say = function(){
      var msg = this.begining.txt + Middle.txt + Ending.txt;
      console.log(msg);
   }
}
/*
   This txt variable will be the "begining" text. It could still be a composite, but
   only if it's not used in another composite when purpose is to be 
   "an untransferable part" and not a "visitor".
*/
var txt = new Text("Dan");
var say1 = new Hello(txt);
var say2 = new Hello(new Text("To be or not to be"));

say1.Say()  /*Dan - that's all.*/
say2.Say() /*To be or not to be - that's all.*/

但是当人们看到 "cars" 有 "wheels" 作为部分(而不是 "visitors")

时,即使是可转移性也常常是一个被忽视的规则

而不是 "neural network" 和 "neurons" 或 "forest" 和 "trees"。树木不会经常被重新种植到不同的森林。

并且由于轮子仍然可以理解为复合材料的一部分,因此它与代码中的聚合没有区别。