Add two methods to the interface, undecorate () and removeDecoration (String className):
ThingInterface.java
public interface ThingInterface { public ThingInterface undecorate(); public ThingInterface removeDecoration(String className); public String nonDecoratedString(); public String decoratedString(); }
Your base class will simply return for these methods:
BaseThing.java
public class BaseThing implements ThingInterface { private String basicString; public BaseThing(String string) { basicString = string; } @Override public ThingInterface undecorate() { return this; } @Override public ThingInterface removeDecoration(String className) { return this; } @Override public String nonDecoratedString() { return basicString; } @Override public String decoratedString() { return basicString; } }
Now the real meat of what you need is in an abstract class:
AbstractThingDecorator.java
public abstract class AbstractThingDecorator implements ThingInterface { private ThingInterface thing; public AbstractThingDecorator(ThingInterface thing) { this.thing = thing; } @Override public ThingInterface removeDecoration(String className) { ThingInterface undecorate = this; if(this.getClass().getName() == className) { undecorate = this.undecorate(); } else { ArrayList<String> classStack = new ArrayList(); while(undecorate != undecorate.undecorate()) { if(undecorate.getClass().getName() != className) { classStack.add(undecorate.getClass().getName()); } undecorate = undecorate.undecorate(); } for(int i = classStack.size()-1;i == 0;i--) { try { Class<?> clazz = Class.forName(classStack.get(i)); Constructor<?> ctor = clazz.getConstructor(ThingInterface.class); Object object = ctor.newInstance(new Object[] { undecorate }); undecorate = (ThingInterface) object; } catch(Exception e) { System.out.println("Exception:" + e.getMessage()); } } } return undecorate; } @Override public ThingInterface undecorate() { return this.thing; } @Override public String nonDecoratedString() { return thing.nonDecoratedString(); } @Override public String decoratedString() { return thing.decoratedString(); } }
I add two simple decorators: ThingDecorator and FancyThingDecorator:
ThingDecorator.java
public class ThingDecorator extends AbstractThingDecorator { public ThingDecorator(ThingInterface thing) { super(thing); } @Override public ThingInterface undecorate() { return super.undecorate(); } @Override public String decoratedString() { return super.decoratedString() + ", decorated"; } }
FancyThingDecorator.java
public class FancyThingDecorator extends AbstractThingDecorator { public FancyThingDecorator(ThingInterface thing) { super(thing); } @Override public ThingInterface undecorate() { return super.undecorate(); } @Override public String decoratedString() { return super.decoratedString() + ", fancy"; } }
Finally, my main part is java:
Decorator.java
public class Decorator { public static void main(String[] args) { ThingInterface thing = new BaseThing("Basic string"); ThingInterface decorator = new ThingDecorator(thing); ThingInterface fancyDecorator = new FancyThingDecorator(thing); ThingInterface extraFancy = new FancyThingDecorator(new ThingDecorator(thing)); ThingInterface undecorate = new FancyThingDecorator(new ThingDecorator(thing)); System.out.println("Basic thing is: " + thing.decoratedString()+"."); System.out.println("Decorated thing is: " + decorator.decoratedString()+"."); System.out.println("Fancy thing is: " + fancyDecorator.decoratedString()+"."); System.out.println("Decorated fancy thing is: " + extraFancy.decoratedString()+"."); while(extraFancy.undecorate() != extraFancy) { extraFancy = extraFancy.undecorate(); System.out.println("Rolling back decorations: " + extraFancy.decoratedString()+"."); } System.out.println("Decoration chain before removal is: " + undecorate.decoratedString()); System.out.println("Removing decoration for " + ThingDecorator.class.getName()); undecorate = undecorate.removeDecoration(ThingDecorator.class.getName()); System.out.println("Decoration chain after removal is: " + undecorate.decoratedString()+"."); } }
Output:
The main thing: the main line.
Decorated item: main line, decorated.
Unusual thing: the main line, fantasy.
Decorated fancy thing: main line, decorated, fantasy.
Rollback decoration: main line, decorated.
Rollback jewelry: the main line.
Jewelry chain before removal: main line, decorated, fancy
Removing Scenery for ThingDecorator
Decoration chain after removal: main line, fantasy.