How to remove a decorated object from a Decorator template in Java

I read "Design Template for Dummies". I read and practiced the Decorator pattern. With Decorator Pattern we can decorate an object with anything. Now I want to remove the decorated object before decorating. I solved this problem with an ArrayList, but I still feel this is not good. Can you tell me how to remove a decorated object? And which is better?

this is my way:

Computer.java

public class Computer { public Computer() { } public String description() { return "computer"; } } 

ComponentDecorator.java

 public abstract class ComponentDecorator extends Computer { @Override public abstract String description(); } 

Cd.java

 public class CD extends ComponentDecorator { private Computer computer; public CD() { } public CD(Computer computer) { this.computer = computer; } @Override public String description() { return computer.description() + " and a CD"; } } 

Disk.java

 public class Disk extends ComponentDecorator { private Computer computer; public Disk() { } public Disk(Computer c) { computer = c; } @Override public String description() { return computer.description() + " and a disk"; } } 

Monitor.java

 public class Monitor extends ComponentDecorator { private Computer computer; public Monitor() { } public Monitor(Computer computer) { this.computer = computer; } @Override public String description() { return computer.description() + " and a monitor"; } } 

Main.java

 import java.util.ArrayList; import java.util.Arrays; public class Main { static ArrayList<ComponentDecorator> list = new ArrayList<>(); public static void main(String[] args) { addComponent(new CD(), new Disk(), new Monitor()); System.out.println(list.size()); Computer penIII = getComputer(); removeComponent(new Monitor()); penIII = getComputer(); System.out.println(penIII.description()); } private static void addComponent(ComponentDecorator... comp) { list.addAll(Arrays.asList(comp)); } private static void removeComponent(ComponentDecorator comp) { for(ComponentDecorator c : list) { if(c.getClass() == comp.getClass()) { list.remove(list.indexOf(c)); break; } } } private static Computer getComputer() { Computer c = new Computer(); Class e; for(ComponentDecorator d : list) { e = d.getClass(); try { c = (Computer) e.getConstructor(new Class[]{Computer.class}).newInstance(c); } catch(Exception ex) { ex.printStackTrace(); } } return c; } } 
+2
source share
3 answers

It is best to add the removeDecorator method to the ComponentDecorator class.

 public abstract class ComponentDecorator { private ComponentDecorator subject; public ComponentDecorator(ComponentDecorator subject) { this.subject = subject; } @Override public abstract String description(); } public void removeDecorator(ComponentDecorator toRemove) { if (subject == null) { return; } else if (subject.equals(toRemove)) { subject = subject.getSubject(); } else { subject.removeDecorator(toRemove); } } public ComponentDecorator getSubject() { return subject; } // Computer public class Computer extends ComponentDecorator{ public Computer() { super(null); } public String description() { return "computer"; } // CD public class CD extends ComponentDecorator { public CD(ComponentDecorator computer) { super(computer); } @Override public String description() { return getSubject().description() + " and a CD"; } } // main public static void main(String[] args) { ComponentDecorator penIII = new Computer(); penIII = new CD(penIII); penIII = new Monitor(penIII); System.out.println(penIII.description()); } 

}

If you don’t have a reference to the decorator that you want to remove, you can create another method that will use the class instead.

You need the decorated object to be “ComponentDecorator” instead of “Computer”. I suggest that the Computer class extend ComponentDecorator, and not vice versa.

+6
source

I suspect I don’t understand your question, but to decorate the (internal) object from the decorator, you can simply add the get method to the decorators. Add

public abstract Computer getDecorated();

in ComponentDecorator and

public Computer getDecorated(){return computer;}

for each subclass (CD, Monitor, ...). Is this what you were looking for?

+1
source

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 { /** * @param args */ 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.

+1
source

All Articles