Showing posts with label composition. Show all posts
Showing posts with label composition. Show all posts

Sunday, June 12, 2011

Various relations in software design - Association, Aggregation, Composition, Abstraction, Generalization, Realization, Dependency

We will just discuss about some of the terms used in software engineering, regarding relationship among the objects, and how they are represented in class diagram.

Association

Association is a relationship between two objects. In other words, association defines the multiplicity between objects. You may be aware of one-to-one, one-to-many, many-to-one, many-to-many all these words define an association between objects. Aggregation is a special form of association. Composition is a special form of aggregation.

Example: A Student and a Faculty are having an association. The relationship between a car and a driver is representative of this relationship. The car will have a driver who will be associated with the car for a period of time.

Aggregation

Aggregation is a special case of association. A directional association between objects. When an object ‘has-a’ another object, then you have got an aggregation between them. Direction between them specified which object contains the other object. Aggregation is also called a “Has-a” relationship.

 
A FileReader object that has been created using a File object represents a mutual dependency where the two objects combine to create a useful mechanism for reading characters from a file. The UML symbols for expressing this relationship as shown in following figure which involve a line connecting the two classes with a diamond at the object that represents the greater whole.


Composition

Composition is a special case of aggregation. In a more specific manner, a restricted aggregation is called composition. When an object contains the other object, if the contained object cannot exist without the existence of container object, then it is called composition.

Example: A class contains students. A student cannot exist without a class. There exists composition between class and students. Other example of this is a customer object and its related address object; the address object cannot exist without a customer object. This relationship is shown with a darkened diamond at the object, which represents the greater whole, as shown in the following figure:

Difference between aggregation and composition

Composition is more restrictive. When there is a composition between two objects, the composed object cannot exist without the other object. This restriction is not there in aggregation. Though one object can contain the other object, there is no condition that the composed object must exist. The existence of the composed object is entirely optional. In both aggregation and composition, direction is must. The direction specifies, which object contains the other object.
Example: A Library contains students and books. Relationship between library and student is aggregation. Relationship between library and book is composition. A student can exist without a library and therefore it is aggregation. A book cannot exist without a library and therefore its a composition. For easy understanding I am picking this example. Don’t go deeper into example and justify relationships!

Abstraction

Abstraction is specifying the framework and hiding the implementation level information. Concreteness will be built on top of the abstraction. It gives you a blueprint to follow to while implementing the details. Abstraction reduces the complexity by hiding low level details.
Example: A wire frame model of a car.

Generalization

Generalization uses a “is-a” relationship from a specialization to the generalization class. Common structure and behaviour are used from the specializtion to the generalized class. At a very broader level you can understand this as inheritance. Why I take the term inheritance is, you can relate this term very well. Generalization is also called a “Is-a” relationship.

Example: Consider there exists a class named Person. A student is a person. A faculty is a person. Therefore here the relationship between student and person, similarly faculty and person is generalization.

Realization

Realization is a relationship between the blueprint class and the object containing its respective implementation level details. This object is said to realize the blueprint class. In other words, you can understand this as the relationship between the interface and the implementing class.

Example: A particular model of a car ‘GTB Fiorano’ that implements the blueprint of a car realizes the abstraction.

Dependency

Change in structure or behaviour of a class affects the other related class, then there is a dependency between those two classes. It need not be the same vice-versa. When one class contains the other class it this happens.

Example: Relationship between shape and circle is dependency. The same relationship would exist for a stock transfer object that needed to use a stock item object to get the information on the stock item being transferred. The stock transfer object would have a dependency relationship with the stock item object; the stock transfer object would read the transfer information and could then discard the stock item object and continue processing.

Tuesday, May 24, 2011

Solution to Square rectangle problem

We have already gone through this problem here.
So inheritance is not always useful, but composition may be the key sometimes.

public class Square  
 {  
     private Rectangle r;  
     public void SetWidth (double x) { r.SetWidth (x); r.SetHeight (x); }  
     public void SetHeight (double x) { r.SetWidth (x); r.SetHeight (x); }  
     public void GetWidth () { return r.GetWidth; }  
     public void GetHeight() { return r. GetHeight; }  
     public void GetArea () { return r. GetArea; }  
}

So it solves our problem.

Friday, May 20, 2011

Open Close Principle ( OCP )

The Open-Closed Principle lies at the heart of the object-oriented paradigm. In a sense, we can say that its the goal of our object-oriented designs. Examining a myriad of patterns reveals its application often. It states the following:
Software entities should be open for extension, but closed for modification.

So it has 2 attributes:
  1. Open For Extension - It is possible to extend the behavior of the module as the requirements of the application change (i.e. change the behavior of the module).So classes can be extended
  2. Closed For Modification - Extending the behavior of the module does not result in the changing of the source code or binary code of the module itself.

Example - Violation of OCP
Consider the classes hierarchy:

class Animal
{
     protected String sound;
}

class Cat extends Animal
{
      //getters and setters
}

class Dog extends Animal
{
    //getters and setters
}

Now consider the class, which manages the animals and make them sound.
SoundManager.java
public class SoundManager{
    private List<Animal> animalList;
        
    public SoundManager(){
        animalList = new ArrayList<Animal>();
    }

    public void add(Animal a){
        animalList.add(a);
    }
    public void makeSound(){
        for(Animal a : animalList)
            if(a instanceof Cat)
                makeMew(a);
            else if(a instanceof Dog)
                makeBark(a);
    }
    public void makeMew(Animal a){
        print(a.getSound());
    }
    public void makeBark(Animal a){
        print(a.getSound());
    }

}
Note that this is not a good solution because suppose a new class Lion comes into picture, and it has a sound called roar, you have to edit the code and another if else or switch() to make that work. So it is violation of OCP.

Solution
So a good solution would be to make makeSound function part of class hierarchy itself.

class Animal
{
     protected String sound;
     public abstract void makeSound();  
}

class Cat extends Animal
{
      //getters and setters
     @Override
     public void makeSound(){
          print("mew");
     }
}

class Dog extends Animal
{
    //getters and setters
     @Override
     public void makeSound(){
          print("bark");
     }
}

Now it is much robust to write the above code, no matter how many animals you add.
public class SoundManager{
    private List<Animal> animalList;
        
    public SoundManager(){
        animalList = new ArrayList<Animal>();
    }

    public void add(Animal a){
        animalList.add(a);
    }
    public void makeSound(){
        for(Animal a : animalList)
            a.makeSound();
    }
    //makeBark, makeMew() functionr removed

}

Note of caution
It sems from the 80s and 90s when OO frameworks were built on the principle that everything must inherit from something else and that everything should be subclassable. So for example take a class called Stack in java, it subclasses Vector. So why on earth will you need push and pop if you can directly access element's index?
Joshua Bloch in his famous book "Effective Java" gives the following advice: "Design and document for inheritance, or else prohibit it", and encourages programmers to use the "final" modifier to prohibit subclassing.
So keep in mind, use inheritance only when its compulsory, otherwise try to make your classes final if you feel in future you won't be extending them.

Summary
It should be clear that no significant program can be 100% closed. So we may need to change the code depending on the requirement, but we can try to make our code as robust as possible. Though it comes with experience.

Wednesday, February 16, 2011

Forwarding

In case of composition, each instance method in the new class which contains or is composed of other class, invokes the corresponding method on the contained instance of the existing class and returns the results. This is known as forwarding, and the methods in the new class are known as forwarding methods.

Tuesday, February 1, 2011

Composition vs Inheritance 2

Dynamic binding, polymorphism, and change
When you establish an inheritance relationship between two classes, you get to take advantage of dynamic binding and polymorphism. Dynamic binding means the JVM will decide at runtime which method implementation to invoke based on the class of the object. Polymorphism means you can use a variable of a superclass type to hold a reference to an object whose class is the superclass or any of its subclasses.
One of the prime benefits of dynamic binding and polymorphism is that they can help make code easier to change. If you have a fragment of code that uses a variable of a superclass type, such as Fruit, you could later create a brand new subclass, such as Banana, and the old code fragment will work without change with instances of the new subclass. If Banana overrides any of Fruit's methods that are invoked by the code fragment, dynamic binding will ensure that Banana's implementation of those methods gets executed. This will be true even though class Banana didn't exist when the code fragment was written and compiled.
Thus, inheritance helps make code easier to change if the needed change involves adding a new subclass. This, however, is not the only kind of change you may need to make.
Changing the superclass interface
In an inheritance relationship, superclasses are often said to be "fragile," because one little change to a superclass can ripple out and require changes in many other places in the application's code. To be more specific, what is actually fragile about a superclass is its interface. If the superclass is well-designed, with a clean separation of interface and implementation in the object-oriented style, any changes to the superclass's implementation shouldn't ripple at all. Changes to the superclass's interface, however, can ripple out and break any code that uses the superclass or any of its subclasses. What's more, a change in the superclass interface can break the code that defines any of its subclasses.
For example, if you change the return type of a public method in class Fruit (a part of Fruit's interface), you can break the code that invokes that method on any reference of type Fruit or any subclass of Fruit. In addition, you break the code that defines any subclass of Fruit that overrides the method. Such subclasses won't compile until you go and change the return value of the overridden method to match the changed method in superclass Fruit.
Inheritance is also sometimes said to provide "weak encapsulation," because if you have code that directly uses a subclass, such as Apple, that code can be broken by changes to a superclass, such as Fruit. One of the ways to look at inheritance is that it allows subclass code to reuse superclass code. For example, if Apple doesn't override a method defined in its superclass Fruit, Apple is in a sense reusing Fruit's implementation of the method. But Apple only "weakly encapsulates" the Fruit code it is reusing, because changes to Fruit's interface can break code that directly uses Apple.

Composition vs Inheritance

The composition alternative
Given that the inheritance relationship makes it hard to change the interface of a superclass, it is worth looking at an alternative approach provided by composition. It turns out that when your goal is code reuse, composition provides an approach that yields easier-to-change code.
Code reuse via inheritance
For an illustration of how inheritance compares to composition in the code reuse department, consider this very simple example:

class Fruit {

    // Return int number of pieces of peel that
    // resulted from the peeling activity.
    public int peel() {

        System.out.println("Peeling is appealing.");
        return 1;
    }
}

class Apple extends Fruit {
}

class Example1 {

    public static void main(String[] args) {

        Apple apple = new Apple();
        int pieces = apple.peel();
    }
}
When you run the Example1 application, it will print out "Peeling is appealing.", because Apple inherits (reuses) Fruit's implementation of peel(). If at some point in the future, however, you wish to change the return value of peel() to type Peel, you will break the code for Example1. Your change to Fruit breaks Example1's code even though Example1 uses Apple directly and never explicitly mentions Fruit.
Here's what that would look like:

class Peel {

    private int peelCount;

    public Peel(int peelCount) {
        this.peelCount = peelCount;
    }

    public int getPeelCount() {

        return peelCount;
    }
    //...
}

class Fruit {

    // Return a Peel object that
    // results from the peeling activity.
    public Peel peel() {

        System.out.println("Peeling is appealing.");
        return new Peel(1);
    }
}

// Apple still compiles and works fine
class Apple extends Fruit {
}

// This old implementation of Example1
// is broken and won't compile.
class Example1 {

    public static void main(String[] args) {

        Apple apple = new Apple();
        int pieces = apple.peel();
    }
}
Code reuse via composition
Composition provides an alternative way for Apple to reuse Fruit's implementation of peel(). Instead of extending Fruit, Apple can hold a reference to a Fruit instance and define its own peel() method that simply invokes peel() on the Fruit. Here's the code:

class Fruit {

    // Return int number of pieces of peel that
    // resulted from the peeling activity.
    public int peel() {

        System.out.println("Peeling is appealing.");
        return 1;
    }
}

class Apple {

    private Fruit fruit = new Fruit();

    public int peel() {
        return fruit.peel();
    }
}

class Example2 {

    public static void main(String[] args) {

        Apple apple = new Apple();
        int pieces = apple.peel();
    }
}
In the composition approach, the subclass becomes the "front-end class," and the superclass becomes the "back-end class." With inheritance, a subclass automatically inherits an implemenation of any non-private superclass method that it doesn't override. With composition, by contrast, the front-end class must explicitly invoke a corresponding method in the back-end class from its own implementation of the method. This explicit call is sometimes called "forwarding" or "delegating" the method invocation to the back-end object.
The composition approach to code reuse provides stronger encapsulation than inheritance, because a change to a back-end class needn't break any code that relies only on the front-end class. For example, changing the return type of Fruit's peel() method from the previous example doesn't force a change in Apple's interface and therefore needn't break Example2's code.
Here's how the changed code would look:

class Peel {

    private int peelCount;

    public Peel(int peelCount) {
        this.peelCount = peelCount;
    }

    public int getPeelCount() {

        return peelCount;
    }
    //...
}

class Fruit {

    // Return int number of pieces of peel that
    // resulted from the peeling activity.
    public Peel peel() {

        System.out.println("Peeling is appealing.");
        return new Peel(1);
    }
}

// Apple must be changed to accomodate
// the change to Fruit
class Apple {

    private Fruit fruit = new Fruit();

    public int peel() {

        Peel peel = fruit.peel();
        return peel.getPeelCount();
    }
}

// This old implementation of Example2
// still works fine.
class Example1 {

    public static void main(String[] args) {

        Apple apple = new Apple();
        int pieces = apple.peel();
    }
}
This example illustrates that the ripple effect caused by changing a back-end class stops (or at least can stop) at the front-end class. Although Apple's peel() method had to be updated to accommodate the change to Fruit, Example2 required no changes.

Comparing composition and inheritance 4


So how exactly do composition and inheritance compare? Here are several points of comparison:

  • It is easier to change the interface of a back-end class (composition) than a superclass (inheritance). As the previous example illustrated, a change to the interface of a back-end class necessitates a change to the front-end class implementation, but not necessarily the front-end interface. Code that depends only on the front-end interface still works, so long as the front-end interface remains the same. By contrast, a change to a superclass's interface can not only ripple down the inheritance hierarchy to subclasses, but can also ripple out to code that uses just the subclass's interface.
  • It is easier to change the interface of a front-end class (composition) than a subclass (inheritance). Just as superclasses can be fragile, subclasses can be rigid. You can't just change a subclass's interface without making sure the subclass's new interface is compatible with that of its supertypes. For example, you can't add to a subclass a method with the same signature but a different return type as a method inherited from a superclass. Composition, on the other hand, allows you to change the interface of a front-end class without affecting back-end classes.
  • Composition allows you to delay the creation of back-end objects until (and unless) they are needed, as well as changing the back-end objects dynamically throughout the lifetime of the front-end object. With inheritance, you get the image of the superclass in your subclass object image as soon as the subclass is created, and it remains part of the subclass object throughout the lifetime of the subclass.
  • It is easier to add new subclasses (inheritance) than it is to add new front-end classes (composition), because inheritance comes with polymorphism. If you have a bit of code that relies only on a superclass interface, that code can work with a new subclass without change. This is not true of composition, unless you use composition with interfaces. Used together, composition and interfaces make a very powerful design tool. I'll talk about this approach in next month's Design Techniques article.
  • The explicit method-invocation forwarding (or delegation) approach of composition will often have a performance cost as compared to inheritance's single invocation of an inherited superclass method implementation. I say "often" here because the performance really depends on many factors, including how the JVM optimizes the program as it executes it.
  • With both composition and inheritance, changing the implementation (not the interface) of any class is easy. The ripple effect of implementation changes remain inside the same class.

Inheritance vs Composition

Choosing between composition and inheritance
So how do all these comparisons between composition and inheritance help you in your designs? Here are a few guidelines that reflect how I tend to select between composition and inheritance.
Make sure inheritance models the is-a relationship
My main guiding philosophy is that inheritance should be used only when a subclass is-a superclass. In the example above, an Apple likely is-a Fruit, so I would be inclined to use inheritance.
An important question to ask yourself when you think you have an is-a relationship is whether that is-a relationship will be constant throughout the lifetime of the application and, with luck, the lifecycle of the code. For example, you might think that an Employee is-a Person, when really Employee represents a role that a Person plays part of the time. What if the person becomes unemployed? What if the person is both an Employee and a Supervisor? Such impermanent is-a relationships should usually be modelled with composition.
Don't use inheritance just to get code reuse
If all you really want is to reuse code and there is no is-a relationship in sight, use composition.
Don't use inheritance just to get at polymorphism
If all you really want is polymorphism, but there is no natural is-a relationship, use composition with interfaces.

Monday, January 31, 2011

Composition Vs Inheritance 1

One of the fundamental activities of any software system design is establishing relationships between classes. Two fundamental ways to relate classes are inheritance and composition. Although the compiler and Java virtual machine (JVM) will do a lot of work for you when you use inheritance, you can also get at the functionality of inheritance when you use composition. This article will compare these two approaches to relating classes and will provide guidelines on their use.
First, some background on the meaning of inheritance and composition.
About inheritance
In this article, I'll be talking about single inheritance through class extension, as in:

class Fruit {

    //...
}

class Apple extends Fruit {

    //...
}
In this simple example, class Apple is related to class Fruit by inheritance, because Apple extends Fruit. In this example, Fruit is the superclass and Apple is the subclass.
I won't be talking about multiple inheritance of interfaces through interface extension. That topic I'll save for next month's Design Techniques article, which will be focused on designing with interfaces.
Here's a UML diagram showing the inheritance relationship between Apple and Fruit:



Inheritance relationship
Figure 1. The inheritance relationship
About composition
By composition, I simply mean using instance variables that are references to other objects. For example:

class Fruit {

    //...
}

class Apple {

    private Fruit fruit = new Fruit();
    //...
}
In the example above, class Apple is related to class Fruit by composition, because Apple has an instance variable that holds a reference to a Fruit object. In this example, Apple is what I will call the front-end class and Fruit is what I will call the back-end class. In a composition relationship, the front-end class holds a reference in one of its instance variables to a back-end class.
The UML diagram showing the composition relationship has a darkened diamond, as in:


Composition relationship
Figure 2. The composition relationship

Chitika