Моделът на декоратора в Java

1. Общ преглед

Модел на декоратор може да се използва за придаване на допълнителни отговорности на обект или статично, или динамично. Декораторът осигурява подобрен интерфейс към оригиналния обект.

При изпълнението на този модел ние предпочитаме композицията пред наследството - така че да можем отново и отново да намалим режийните разходи за подкласиране за всеки елемент за декориране. Рекурсията, свързана с този дизайн, може да се използва за украса на нашия обект толкова пъти, колкото ни е необходимо.

2. Пример за модел на декоратор

Да предположим, че имаме обект за коледно дърво и искаме да го украсим. Декорацията не променя самия предмет; просто в допълнение към коледното дърво, ние добавяме и някои декоративни елементи като гирлянд, мишура, горнище, балончета и т.н .:

За този сценарий ще следваме оригиналните конвенции за проектиране и именуване на Gang of Four. Първо ще създадем интерфейс ChristmasTree и неговото изпълнение:

public interface ChristmasTree { String decorate(); }

Внедряването на този интерфейс ще изглежда така:

public class ChristmasTreeImpl implements ChristmasTree { @Override public String decorate() { return "Christmas tree"; } }

Сега ще създадем абстрактен клас TreeDecorator за това дърво. Този декоратор ще приложи интерфейса ChristmasTree, както и ще съхранява същия обект. Внедреният метод от същия интерфейс просто ще извика метода deco () от нашия интерфейс:

public abstract class TreeDecorator implements ChristmasTree { private ChristmasTree tree; // standard constructors @Override public String decorate() { return tree.decorate(); } }

Сега ще създадем елемент за декориране. Тези декоратори ще разширят нашия абстрактен клас TreeDecorator и ще модифицират метода си deco () според нашето изискване:

public class BubbleLights extends TreeDecorator { public BubbleLights(ChristmasTree tree) { super(tree); } public String decorate() { return super.decorate() + decorateWithBubbleLights(); } private String decorateWithBubbleLights() { return " with Bubble Lights"; } }

В този случай важи следното:

@Test public void whenDecoratorsInjectedAtRuntime_thenConfigSuccess() { ChristmasTree tree1 = new Garland(new ChristmasTreeImpl()); assertEquals(tree1.decorate(), "Christmas tree with Garland"); ChristmasTree tree2 = new BubbleLights( new Garland(new Garland(new ChristmasTreeImpl()))); assertEquals(tree2.decorate(), "Christmas tree with Garland with Garland with Bubble Lights"); }

Имайте предвид, че в първия Tree1 обекта, ние сме само украсявайки го само с един Гарланд , а другата tree2 обект сме украсили с един BubbleLights и две гирлянди . Този модел ни дава тази гъвкавост да добавяме толкова декоратори, колкото искаме по време на изпълнение.

4. Заключение

В тази статия разгледахме дизайна на декоратора. Това е добър избор в следните случаи:

  • Когато искаме да добавим, подобрим или дори премахнем поведението или състоянието на обектите
  • Когато просто искаме да модифицираме функционалността на един обект от класа и да оставим другите непроменени

Пълният изходен код за този пример е достъпен в GitHub.