Описание:
Паттерн Декоратор необходим для построения систем-“матрёшек”, где каждый класс можно завернуть в другой, тем самым расширив его функционал. Расширение осуществляется посредством нехитрой композиции.
Пример:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
public class Main { public static void main(String[] args){ Component computer = new Computer(); computer = new Keyboard(computer); computer = new Mouse(computer); computer = new Memory(computer); computer = new Memory(computer); System.out.println("Order for my computer"); for (String part : computer.getDescription()){ System.out.println("Component: "+part); } System.out.println("Total cost: "+computer.getCost()); } } |
1 2 3 4 5 6 7 |
Order for my computer Component: My computer Component: Logitech Keyboard K200 Component: SteelSeries Sensei MLG 62153 Black Component: Toshiba STOR.E 1TB Component: Toshiba STOR.E 1TB Total cost: 50270.0 |
Коды классов:
1 2 3 4 |
public interface Component { public ArrayList<string> getDescription(); public double getCost(); } |
1 2 3 |
public interface ComponentDecorator extends Component { public void setWrapped(Component c); } |
1 2 3 4 5 6 7 8 9 10 11 12 13 |
public class Computer implements Component { @Override public ArrayList<string> getDescription() { ArrayList<string> arrayList = new ArrayList<string>(); arrayList.add("My computer"); return arrayList; }</string></string></string> @Override public double getCost() { return 33000.0; } } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
public class Keyboard implements ComponentDecorator { Component wrapped; public Keyboard(Component c){ setWrapped(c); } @Override public void setWrapped(Component c) { this.wrapped = c; } @Override public ArrayList<string> getDescription() { ArrayList<string> arrayList = wrapped.getDescription(); arrayList.add("Logitech Keyboard K200"); return arrayList; }</string></string> @Override public double getCost() { return wrapped.getCost() + 820.; } } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
public class Mouse implements ComponentDecorator { Component wrapped; public Mouse(Component c){ setWrapped(c); } @Override public void setWrapped(Component c) { this.wrapped = c; } @Override public ArrayList<string> getDescription() { ArrayList<string> arrayList = wrapped.getDescription(); arrayList.add("SteelSeries Sensei MLG 62153 Black"); return arrayList; }</string></string> @Override public double getCost() { return wrapped.getCost() + 7190.; } } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
public class Memory implements ComponentDecorator { Component wrapped; public Memory(Component c){ setWrapped(c); } @Override public void setWrapped(Component c) { this.wrapped = c; } @Override public ArrayList<string> getDescription() { ArrayList<string> arrayList = wrapped.getDescription(); arrayList.add("Toshiba STOR.E 1TB"); return arrayList; }</string></string> @Override public double getCost() { return wrapped.getCost() + 4630.; } } |
UML-диаграмма:
Паттерн Декоратор используется в java.io, поэтому в этом пакете так много классов.
Пример своего декоратора для чтения из потока:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
public class CodecInputStream extends FilterInputStream { protected CodecInputStream(InputStream in) { super(in); } @Override public int read() throws IOException { byte c = (byte) super.read(); byte newC = (byte)(c - 64); if (newC < 0){ newC = (byte)(128 + newC); } return c == -1 ? c : newC; } @Override public int read(byte[] b, int off, int len) throws IOException { for (int i = 0; i < b.length; i++) { b[i] = (byte)(b[i] - 64); if (b[i] < 0){ b[i] = (byte)(128 + b[i]); } } return super.read(b, off, len); } } |
Декоратор кодирует ASCII символы (для декодирования нужно пропустить текст через наш класс дважды).
Паттерн Декоратор