DesignPattern: Composite Pattern

Composite Design Pattern

1) Motivation:

        There are many times when a program need to manipulate a tree data structure and it is necessary to treat both Branches as well as Leaf Nodes uniformly.

        Consider for example a program that manipulates a file system. A file system is a tree structure that contains Branches which are folders as well as Leaf Nodes which are files.

        Note that a folder object ususally contains one or more files or folder objects and thus is a complex object where a file is a simple object.

        Note also that since files and folders had many operations and attributes in common, such as moving or copying a file or a folder, listing file or folder attributes such as file name and size.

        It would be easier and more convenient to treat both file and folder objects uniformly by defining a File System Resource Interface.

2) Intent:

        The intent of this pattern is to compose objects into tree structures to represent part-whole hierarchies.

        Composite lets client treat individual objects and compositions objects uniformly.

3) Implementation:


    1> Component:

         Component is the abstraction of leafs and composites. It defines the interface that must be implemented by the object in the composition.

         For example, a file resource system defines move, copy, reName and getSize methods for files and folders.

    2> Leaf:

         Leafs are objects that have no children. They implement services described by the Component interface.

         For example, a file object implements move, copy, reName as well as getSize methods which are related to the component interface.

    3> Composite:

         A composite stores child components in addition to implementing methods defined by the Component interface.

         Composites implements methods defined in the Component interface by delegating to child components.

         In addition, composites provide additional methods for adding, removing as well as getting components.

    4> Client:

         The Cilent manipulate objects in the hierarchy using the Component interface.

         A Client has a reference to a tree data structure and needs to perform operations on all nodes independent of the fact that a node might be a brach or a leaf.

        The Client simply obtains a reference to the required node using the Component interface, and deals with the node using the interface.

         It doesn't matter if the node is a Leaf or a Composite.

4) Applicablity & Examples:

    The composite pattern applies when there is a part-whole hierarchy of objects and a client needs to deal with object uniformly regardless of the fact that an object might be a leaf or a branch.

    Example: Graphics Drawing Editor

        In graphics editors a shape can be basic or complex.

       An example of a simple shape is a Line, where a complex shape is a rectangle which is made of four Line objects. 

       Since shapes have many operations in common such as rendering the shape to screen,

       and since shapes follow a part-whole hierarchy, composite pattern can be used to enable the program to deal with all shapes uniformly.



package edu.xmu.oop.composite;

public interface Shape {
    public void render();
}
package edu.xmu.oop.composite;

public class LineShape implements Shape {
    public void render() {
	System.out.println("Render [LineShape]");
    }
}
package edu.xmu.oop.composite;

public class RectangleShape implements Shape {
    public void render() {
	System.out.println("Render [RectangleShape]");
    }
}
package edu.xmu.oop.composite;

import java.util.ArrayList;
import java.util.List;

public class ComplexShape implements Shape {
    private List<Shape> components = new ArrayList<Shape>();

    public void render() {
	System.out.println("Start render [ComplexShape]");
	for (Shape shape : components) {
	    shape.render();
	}
	System.out.println("Finished render [ComplexShape]");
    }

    public void addComponent(Shape shape) {
	components.add(shape);
    }

    public void removeComponent(Shape shape) {
	components.remove(shape);
    }
}
package edu.xmu.oop.composite;

public class GraphicsEditor {
    public void display(Shape shape) {
	shape.render();
    }
}
package edu.xmu.oop.composite;

import org.junit.Before;
import org.junit.Test;

public class GraphicsEditorTest {
    private GraphicsEditor graphicsEditor;
    private Shape complexShape1;

    @Before
    public void setUp() {
	graphicsEditor = new GraphicsEditor();
	complexShape1 = new ComplexShape();
	((ComplexShape) complexShape1).addComponent(new LineShape()); // We have to cast complexShape1 to ComplexShape
	((ComplexShape) complexShape1).addComponent(new RectangleShape());// We have to cast complexShape1 to ComplexShape

	Shape complexShape2 = new ComplexShape();
	((ComplexShape) complexShape2).addComponent(new LineShape());// We have to cast complexShape2 to ComplexShape
	((ComplexShape) complexShape2).addComponent(new LineShape());// We have to cast complexShape2 to ComplexShape
	((ComplexShape) complexShape2).addComponent(new RectangleShape());// We have to cast complexShape2 to ComplexShape
	((ComplexShape) complexShape1).addComponent(complexShape2);// We have to cast complexShape1 to ComplexShape
    }

    @Test
    public void displayTest() {
	graphicsEditor.display(complexShape1);
    }
}

    And we can see in the diagram below that the objects are organized as a tree.




5) Alternative Implementations:

        Note that in previous example, there were times when we have to avoid dealing with composite objects through the Shape interface, 

        And we have specifically dealt with them as composites(when using the method addComponent()).

        To avoid such situations and to further increase uniformity, one can add method to add, remove and get child components to the Shape interface. 

6) Related Patterns:

    1> Decorator Pattern:

         Decorator is often used with Composite.

         When Decorator and Composite are used together, they will usually have a common parent class, 

         So Decorator will have to support the Component interface with operations like Add, Remove and GetChild.

Reference Links:

1) http://www.oodesign.com/composite-pattern.html

2) http://en.wikipedia.org/wiki/Composite_pattern

猜你喜欢

转载自davyjones2010.iteye.com/blog/2088747
今日推荐