Как удалить оформленный объект из Pattern Decorator в Java

2

Я читаю "Шаблон дизайна для чайников". Я читал и практиковал узор Декоратора. С 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;
    }
}
Теги:
design-patterns
decorator

3 ответа

6

Лучше всего добавить метод 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, а не наоборот.

  • 0
    Можете ли вы опубликовать свой отредактированный код?
1

Добавьте два метода в интерфейс, 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

Цепочка украшения после удаления: основная строка, фантазия.

  • 0
    На данный момент, хотя ... не то, что у вас больше похоже на перехватчик, чем декоратор?
1

Я подозреваю, что не понимаю ваш вопрос, но чтобы украсить (внутренний) объект из декоратора, вы можете просто добавить метод get к декораторам. Добавить

public abstract Computer getDecorated();

в ComponentDecorator и

public Computer getDecorated(){return computer;}

для каждого подкласса (CD, Monitor,...). Это то, что вы искали?

  • 0
    Извините, я плохо разбираюсь в английском. Это означает, что я украшаю объект и хочу удалить объект, который был украшен ранее. Например: у меня есть компьютер, затем я добавляю его на жесткий диск, экран и привод компакт-дисков. Но через мгновение я вынимаю CD-дисковод, а на моем компьютере только монитор и жесткий диск. На устройствах удалены случайные и варианты. Я ищу наиболее оптимальное решение этой проблемы
  • 0
    спасибо за ваш ответ, но я не хочу получать украшенный предмет. Я хочу получить декорированный предмет раньше, когда уберу декоратор. public Computer getDecorated () {return computer;} Этот метод возвращает декорированный объект, в этом нет необходимости, поскольку конструктор уже делает это
Показать ещё 1 комментарий

Ещё вопросы

Сообщество Overcoder
Наверх
Меню