Search code examples
ooplanguage-agnosticobject-oriented-analysisooad

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


How can an object inside another object and the first object re-use the code behind the composed object And what is mean by composed object can be determined at run-time?

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( );
}

I don't know whether I'm going in the right direction or not, I wanted to know the meaning of "composed object can be determined at Run-time?" Here Button is composed in calculator class


Solution

  • This principle is demonstrated in Effective Java Book as 'Item 16'. I think when it is said "Favor Composition over Inheritance for code reuse", 'Composition' word is used as synonym of 'Containment' or 'association' and not in the spirit of true composition of UML. "Effective Java" by Joshua Bloch, provides good example under 'Item 16'.

    In the demo example in above book, instance for containment (Subclass of Set) is passed through constructor and could always be cached outside (by client) breaking the composition. In book's demo as well it is case of containment and not a pure Composition (where composed object is not known outside).

    Code reuse can be achieved by two mechanisms namely 'Inheritance (White box)' and 'Containment (Black box)'. In case of black box reuse, we (can) couple the reusable class at run time by assigning an instance of child class against a reference of Abstract base class/ Interface. In principle Inheritance should be used only when there is 'IsA' relationship and we want to use objects interchangeability and obtain the advantages of polymorphic behavior.

    In your example though Calculator is using Button, its not expecting dynamic child class instances. But when we say addActionListener(), Button class will be making use of ActionListener by Containment as 'Button Is NOT a Kind of ActionListener" instead Button 'uses' ActionListener.

    Here is an example of code reuse by Composition. Observe that instance of List is not known from outside the PackOfCards, but internally PackOfCards is delegating all functionality to Concrete List. When the Object of PackOfCards is destroyed, List also gets destroyed. But here we will not be able to change the concrete List dynamically from outside due to '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
    }