Composition(又名关联)如何成为实现重用的另一种方式?

How Composition (aka association) is another means of achieving re-use?

另一个对象和第一个对象中的对象如何重用组合对象背后的代码以及组合对象的含义可以在 运行 时确定?

class Calculator
{
    private:
        long double operand_1;
        long double operand_2;
        long double result;
        int optr;
        int multiplier;
        Button One;
        //Button Two..
        //..through Nine
        Button Zero;
}

class Button
{
    private:
        int x1;
        int y1;
        int x2;
        int y2;
        char Label[55];

    public:
        Button( );
        int hit( );
        void show( );
        void press( );
        void select( );
}

我不知道我的方向是否正确,我想知道“组合对象可以在运行时确定的含义?" 这里的Button是在计算器中组成的class

这个原则在 Effective Java Book as 'Item 16' 中得到了证明。我认为当说 "Favor Composition over Inheritance for code reuse" 时,'Composition' 一词被用作 'Containment' 或 'association' 的同义词,而不是本着 UML 真正组成的精神。 "Effective Java" 作者 Joshua Bloch,在 'Item 16' 下提供了很好的例子。

在上面书中的演示示例中,包含实例(Set 的 Subclass)通过构造函数传递,并且始终可以(由客户端)在外部缓存,从而破坏了组合。在本书的演示中,它也是包含而不是纯组合的情况(其中组合对象在外部是未知的)。

代码重用可以通过两种机制实现,即'Inheritance (White box)'和'Containment (Black box)'。在黑盒重用的情况下,我们(可以)通过将子 class 的实例分配给抽象基 class/ 接口的引用,在 运行 时耦合可重用的 class .原则上只有在存在'IsA'关系时才应该使用继承,并且我们希望利用对象的互换性并获得多态行为的优势。

在您的示例中,虽然计算器使用的是 Button,但它不期望动态子 class 实例。但是当我们说 addActionListener() 时,Button class 将通过 Containment 使用 ActionListener,因为“Button Is NOT a Kind of ActionListener”而不是 Button 'uses' ActionListener.

这里有一个代码重用的例子。观察到 List 的实例在 PackOfCards 外部是未知的,但 PackOfCards 在内部将所有功能委托给 Concrete List。当 PackOfCards 的对象被销毁时,List 也被销毁。但是由于'composition'.

,这里我们将无法从外部动态更改具体列表
public class Card {
    public enum Suit{SPADE, HEART,DIAMOND,CLUB}
    public enum Rank{ACE,QUEEN,KING}// and others
    private Suit suit;
    private Rank rank;
    public Card(Suit suit, Rank rank) {
        this.suit = suit;
        this.rank = rank;
    }
}
public class PackOfCards {
    private List<Card> cards;

    public PackOfCards() {
        cards = new LinkedList<Card>();
    }

    public Card getCard(int index){
        return cards.get(index);
    }

    public void shuffle(){
        Collections.shuffle(cards);
    }
    // other methods
}