Я читаю "Шаблон дизайна для чайников". Я читал и практиковал узор Декоратора. С Decorator Pattern мы можем украсить объект чем угодно. Теперь я хочу удалить украшенный объект перед декорированием. Я решил эту проблему с помощью ArrayList, но я все еще чувствую, что это не хорошо. Можете ли вы рассказать мне, как удалить украшенный объект? И что лучше?
это мой путь:
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;
}
}
Лучше всего добавить метод removeDecorator в класс ComponentDecorator.
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());
}
}
Если у вас нет ссылки на декоратор, который вы хотите удалить, вы можете создать другой метод, который вместо этого будет использовать класс.
Вам нужно, чтобы украшенный объект был "ComponentDecorator" вместо "Computer". Я предлагаю, чтобы класс Computer расширил ComponentDecorator, а не наоборот.
Добавьте два метода в интерфейс, undecorate() и removeDecoration (String className):
ThingInterface.java
public interface ThingInterface {
public ThingInterface undecorate();
public ThingInterface removeDecoration(String className);
public String nonDecoratedString();
public String decoratedString();
}
Ваш базовый класс просто вернется для этих методов:
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;
}
}
Теперь реальное мясо того, что вам нужно, находится в абстрактном классе:
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();
}
}
Я добавляю два простых декоратора: ThingDecorator и 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";
}
}
Наконец, моя главная часть 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()+".");
}
}
Вывод:
Основная вещь: основная строка.
Украшенная вещь: основная строка, украшенная.
Необычная вещь: основная строка, фантазия.
Украшенная причудливая вещь: основная строка, украшенная, фантазия.
Откат украшения: основная строка, украшенная.
Откат украшений: основная строка.
Цепь украшения перед удалением: основная строка, украшенная, причудливая
Удаление декораций для ThingDecorator
Цепочка украшения после удаления: основная строка, фантазия.
Я подозреваю, что не понимаю ваш вопрос, но чтобы украсить (внутренний) объект из декоратора, вы можете просто добавить метод get к декораторам. Добавить
public abstract Computer getDecorated();
в ComponentDecorator и
public Computer getDecorated(){return computer;}
для каждого подкласса (CD, Monitor,...). Это то, что вы искали?