组合 vs 内部类

12

组合和内部类有哪些不同和相似之处?我正在尝试学习Java的原则并尝试理清全局思路。对于我来说,最好是通过比喻来看到概念之间的差异和相似之处,以便正确地使用它们。

组合的定义: “组合是一种设计技术,用于在类中实现has-a关系。” “Java组合是通过使用引用其他对象的实例变量来实现的”

内部类(或成员类,非匿名)的定义: “成员类也被定义为封闭类的成员,但没有声明static修饰符。这种类型的内部类类似于实例方法或字段。成员类的实例始终与封闭类的实例相关联,并且成员类的代码可以访问所有字段和方法。”

因此,通过对比这两个定义,我发现了一些相似之处:

1. Both have HAS-A relationship
2. Both are strictly dependent on the outer class lifetime
3. can be declared private

区别:

1. Inner classes uses classes, composition use instances (?!)
2. In composition no restriction to use the variables of the "outer" class

请纠正我如果我完全错了,我需要更好地追踪两个概念的限制。


2
这就像是拿苹果和橙子做比较。你必须有一些共同点来比较两件事情。这就像是拿洗衣机和火车做比较,因为它们都有引擎。你应该阅读示例,展示这两个概念的使用,并查看它们是否都可以用于解决相同领域的问题。 - RealSkeptic
对的。但是你试图在什么基础上进行比较呢?例如,你可以说:“为了解决问题X,我可以使用这个解决方案或那个解决方案,这两个解决方案相似之处在于它们都可以解决问题X,并且可能在其他方面也有相似之处,但在A、B和C方面它们还是不同”。但是你始终从一个共同的基础出发:解决问题X的需求。 - RealSkeptic
@RealSkeptic,如果我在面试中遇到这样的问题需要回答,我可以引用你的话吗? :) - Alexis
你可以这样说,但我怀疑我的昵称不会给面试官留下什么印象... 但请记住,面试问题并不总是为了测试你的知识,而是为了测试你解决问题的思维方式。也许他们期望你意识到没有共同点并且直言不讳。 - RealSkeptic
@RealSkeptic,如果我发现一些概念之间存在相似之处,对我来说就是一个共同点。也许你谈论的是不同的目的。这可能是我的弱点所在。 - Alexis
4个回答

8

这两个概念是相关的。为了更好地组织我的思路,让我们定义 A 和 B:

  • A 是由内部类组成的类成员。
  • B 是由外部类的实例组成的类成员。

例如:

class Driver {
}

class Car {

    // A
    class Engine {
        void start() {
            if (gasLevel > 0) {
                ...
            }
        }
    }

    //B
    Driver driver;

    int gasLevel;

}

话虽如此:

  • A是一个字段
  • B是一个字段
  • A是一个内部类
  • B不是一个内部类
  • A可以访问Car的内部状态(gasLevel)
  • B无法访问Car的内部状态(gasLevel)
  • 没有Car实例就不存在Engine。
  • Driver可以在没有Car实例的情况下存在。

总之,两个不同类之间的组合和与内部类之间的组合是控制系统耦合度和内聚性的方法。


感谢您的详细解释。但是在您的情况下,B不应该是一个关联(或聚合)吗?组合:A由B组成;B是A的一部分,因此不能没有A存在(A拥有B);在您的情况下,Driver可以独立于Car实例而存在。对我来说,这只是一种关联形式(或者更好的聚合):关联:A使用B,A以某种方式与B相关。 - Alexis
我同意我的回答在组合术语上并不严格准确。然而,你最初对组合的定义也不够精确。要精确,我们需要称B为聚合。组合和聚合都是关联。 - Leonardo Cruz
1
我们可以称A为组合,B为聚合。 - Leonardo Cruz
嗨,当 driver 需要知道 gasLevel 时,你会如何处理这种情况?在 Driver 类内放置一个 Car 引用是否是一种好的做法? - parsecer
是的,还要在Car上添加一个setter来公开gasLevel值。请注意,此示例不涉及对象建模的最佳实践。 - Leonardo Cruz

1
你说得对,组合和内部类都实现了“有一个”方案,但它们有很多不同之处。
组合是指你的类将另一个类的实例作为实例变量(有时称为字段)。
public class A {
    B otherObject;
    /* Other fields and methods go here */
}

在这种情况下,otherObject只是指向类型为B的另一个对象实例的引用。otherObject可以独立于A实例存在,并且多个A实例可以引用相同的B。
内部类是指类定义实际上包含在外部类中。
public class C {
    class D {
        /* Inner class stuff goes here */
    }
}

这主要用于逻辑分组。在这种情况下,D直接与C相关联,而B可能是A的逻辑子类,也可能不是。在C之外访问D变得更加复杂,但只能通过现有的C实例访问它。

因此,通过对比两个定义,我发现一些相似之处: ... 3. 可以声明为私有

你说的没错,两者都可以声明为private,但这两者的含义非常不同。在组合中使用的private表示对该引用的访问受到限制,仅限于该类。假设在您的执行代码中,您有一个类型为A的objectA对象。您不能尝试访问objectA.otherObject。otherObject只能从A的主体引用。当您将内部类声明为private时,这意味着该整个类的使用受到限制,仅限于A的主体中。您无法在任何其他类中使用它。


在这个解释中,你混淆了组合和聚合。当一个类O1的对象与另一个类O2的对象相关联,并且O1和O2可以独立存在时,就构成了聚合。通常通过构造函数/设置器将实例提供给引用来完成此操作,而不是在类本身中手动定义它们。如果我说错了,请纠正我。 - chepaiytrath

0

阅读这篇关于组合的博客文章似乎很容易理解......JAVA中的组合


始终在答案中添加相关链接的片段,最好在概括/改写以适应所提出的问题之后。 - LumberHack

0
在组合中,您不能直接访问封闭类的私有字段。 内部类默认可以访问外部类的字段。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接