In software engineering, the design patterns are reusable solutions to a commonly occurring problem within a given context. Currently I am involved in a UML modeling project that needs a design pattern for objects that have the same composition, same code and tree structured data.
Unfortunately, every time I visit customers I find, in most of them, that the software code quality is poor. I will not analyze in this post why this happens because there are many influencing factors such as cost, inexperienced programmers, misdirection, etc..
What I know, is that many programmers do not use development methodologies including the use of pattern matching.
Anyway, I will explain how to use the composite pattern in a few steps, modeling in UML and programming in Java using the based Eclipse tool Rational Software Architect for WebSphere (RSA).
Unfortunately, every time I visit customers I find, in most of them, that the software code quality is poor. I will not analyze in this post why this happens because there are many influencing factors such as cost, inexperienced programmers, misdirection, etc..
What I know, is that many programmers do not use development methodologies including the use of pattern matching.
Anyway, I will explain how to use the composite pattern in a few steps, modeling in UML and programming in Java using the based Eclipse tool Rational Software Architect for WebSphere (RSA).
As brief introduction, the composite pattern describes that a group of objects are to be treated in the same way as a single instance of an object. The intent of a composite is to "compose" objects into tree structures to represent part-whole hierarchies.
More info on
Wikipedia: Composite pattern.
For now I leave the theory aside and I will explain the procedures. I divided the procedures into three steps: modeling, transformation and code execution.
Procedure to create the UML model:
For now I leave the theory aside and I will explain the procedures. I divided the procedures into three steps: modeling, transformation and code execution.
Procedure to create the UML model:
- Open RSA and open the Modeling perspective
- Create a new project. File -> New -> Project...
- Select General -> Project and click Next
- Write in Project name: Composite Pattern and click Finish
- Create a model UML, File -> New -> Model
- Select Standard template and click Next
- Select General -> Blank Package and in File name: org
- Browse Destination folder and select Composite Pattern, click Finish
- On package org, add the following UML packages in cascaded: jif, develop and composite
- Add the following UML classes in composite package: Composite class, Component class and Leaf class and IComponent interface
- Add the following UML interface in composite package: IComponent interface
- Open the Main freeform diagram and drag the UML elements and Save the changes
- Add in IComponent interface the following operations: getName with String value return and without inputs parameters, getParent with IComponent value return and without input parameters, add without return and IComponent as input parameter, remove without return and IComponent as input parameter and getChilds with java.util.Set value return and without input parameters
- Repeat same operations described in the previous step for Composite class
- In the Component class add the following attribute name as String type and protected
- Add in Leaf class the following operations: getName with String value return and without inputs parameters, getParent with Component value return and without input parameters
- Create an Interface Realization from Component to IComponent
- Create a Generalizarion from Composite to Component
- Create a Generalization from Leaf to Component
- Create a Composition Association from Composite to Component
- Save changes
Procedure to transform UML to Java:
- Create a Java project, New -> Other, select in the wizard window the Java Project option and then click Next
- Write the Project name: Composite and click Finish
- In menu, Modeling -> Transform -> New Configuration
- Write in name uml2java and select in Configuration file destination the java project Composite
- In Java Transformations select UML to Java
- Click Next
- Select the Source, Composite Pattern -> Models -> org
- Select the Target, Composite -> src
- Click Finish
- Run the transformation to generate de Java source code
Procedure to run the example:
- Resolve the warnings that transformation has left:- Set is a raw type. References to generic type Set<E> should be parameterized to:Set<IComponent>- In Composite class, initialize the attribute component:private Set<IComponent> component = new HashSet<IComponent>();- Remove the @generated tags
- Implement the Composite class:- Create constructor
public Composite(String name) {super.name = name;}- Add the return value in the getName methodpublic String getName() {return super.name;}- Add array componentspublic void add(IComponent component) {this.component.add(component);}- Add the return value in the getChilds methodpublic Set<IComponent> getChilds() {return component;} - Implement the Leaf class:- Create constructor
public Leaf(String name) {super.name = name;}- Add the return value in the getName methodpublic String getName() {return super.name;} - Create a class (Test.java) to run an example composite pattern:- In the main method,
IComponent componentA = new Composite("ComponentA");IComponent componentB = new Composite("ComponentB");IComponent componentC = new Composite("ComponentC");IComponent componentD = new Composite("ComponentD");IComponent leafA = new Leaf("leafA");IComponent leafB = new Leaf("leafB");IComponent leafC = new Leaf("leafC");IComponent leafD = new Leaf("leafD");componentD.add(leafD);componentC.add(leafC);componentB.add(leafB);componentB.add(componentC);componentA.add(leafA);componentA.add(componentB);componentA.add(componentD);
Composite Pattern example applied to automotive engineering:
Here I leave an example of how it can be applied in the real world.
Source Files:
- IComponent.java
package jif.develop.composite;
import java.util.Set;
/**
* @author Jorge Iglesias
*/
public interface IComponent {
public String getName();
public IComponent getParent();
public void add(IComponent component);
public void remove(IComponent component);
public Set<IComponent> getChilds();
}
- Component.java
package jif.develop.composite;
import java.util.Set;
/**
* @author Jorge Iglesias
*/
public class Component implements IComponent {
protected String name;
public String getName() {
return null;
}
public IComponent getParent() {
return null;
}
public void add(IComponent component) {
}
public void remove(IComponent component) {
}
public Set<IComponent> getChilds() {
return null;
}
}
- Composite.java
package jif.develop.composite;
import java.util.HashSet;
import java.util.Set;
/**
* @author Jorge Iglesias
*/
public class Composite extends Component {
private Set<IComponent> component = new HashSet<IComponent>();
public Composite(String name) {
super.name = name;
}
public String getName() {
return super.name;
}
public IComponent getParent() {
//TODO: to be implemented
return null;
}
public void add(IComponent component) {
this.component.add(component);
}
public void remove(IComponent component) {
//TODO: to be implemented
}
public Set<IComponent> getChilds() {
return component;
}
}
- Leaf.java
package jif.develop.composite;
/**
* @author Jorge Iglesias
*/
public class Leaf extends Component {
public Leaf(String name) {
super.name = name;
}
public String getName() {
return super.name;
}
public IComponent getParent() {
return null;
}
}
- Test.java
package jif.develop.composite;
/**
* @author Jorge Iglesias
*/
public class Test {
public static void main(String[] args) {
IComponent componentA = new Composite("ComponentA");
IComponent componentB = new Composite("ComponentB");
IComponent componentC = new Composite("ComponentC");
IComponent componentD = new Composite("ComponentD");
IComponent leafA = new Leaf("leafA");
IComponent leafB = new Leaf("leafB");
IComponent leafC = new Leaf("leafC");
IComponent leafD = new Leaf("leafD");
componentD.add(leafD);
componentC.add(leafC);
componentB.add(leafB);
componentB.add(componentC);
componentA.add(leafA);
componentA.add(componentB);
componentA.add(componentD);
printTree(componentA,0);
}
static void printTree(IComponent c, int depth) {
String d = "";
for (int i = 0; i < depth; i++) {
d+=" ";
}
System.out.println(d + c.getName());
if (c instanceof Composite) {
if (c.getChilds().size() > 0) {
depth++;
for (IComponent component : c.getChilds()) {
printTree(component, depth);
}
}
}
}
}
Hi, Its really informative post .
ReplyDeleteComposite design pattern is based on creating a tree structure in such a way that an individual leaf of the tree can be treated just like entire tree composition.
Java composite design pattern
OO design pattern
composite tree design
Hi,
ReplyDeleteVery useful post. I am beginner trying to create the above example in my local RSA. While creating the class diagram, as mentioned by you , I tried to use java types like java.util.Set in return type of method, but I am not able to select the same. I am only able to use the model elements created in return type. Please advise how I can use java types from the jre library in the class diagram.
Thanks and Regards,
Anuradha
Thanks Anuradha,
ReplyDeleteAbout your question, you need to extend the UML metamodel for this particular use, instead of changing the metamodel, you can create a set of stereotypes and constraints and group them into a custom UML profile.
Extending the UML metamodel:
- http://pic.dhe.ibm.com/infocenter/rsawshlp/v7r5m0/index.jsp?topic=%2Fcom.ibm.xtools.profiles.doc%2Ftopics%2Ftprofover.html
Thanks for you comment.
Regards,
Jorge