First, the basic concept
The decorator pattern is a structural design pattern.
Decorative pattern to the client transparently extend the function of the object , it is an alternative inheritance relationships.
It allows you to add new functionality to an existing object. While not changing its structure, which is packaged as a conventional class.
The main problem to solve: In general we often use in order to expand a class inheritance to achieve, due to the introduction of inheritance static features as a class, and with the increase of extensions, subclasses will be expanded .
Second, the structure
structure:
Decorator (Decorator), and specific components (ConcreteComponent) are inherited from component (Component);
The so-called decoration, the decorator is to cover over the decorators to dynamically extend the functionality of the decorator;
The method of the decorator part of their own, which is a function of its ( translucent decorator pattern ). Then call the method is implemented decorator, which also retains the function is decorator;
Third, the case
1, the decorator pattern Case
Analog drinks in a restaurant point, we can have some coffee, and coffee haveDecaf
coffee andEspresso
coffee, both of which are coffee with milk and chocolate inside.
FIG particular organization code:
Specific code:
Look at the top component
under the package Drink
category:
/** * Component的超类 * 单品和装饰者都要继承自这个类 */ public abstract class Drink { private String description = ""; //一开始没有描述 private double price = 0; //一开始价格为0 /** * 抽象方法 * 1、如果是单品的话就直接是自己的价格 * 2、如果是装饰者的话就还要加上装饰品自己的价格 */ public abstract double cost(); // setter getter public String getDescription() { return description; } public double getPrice() { return price; } public void setDescription(String description) { //描述的时候顺便把价格描述一下 this.description = description; } public void setPrice(double price) { this.price = price; } }
下面看两个具体的Component
:
/** ConcreteComponent 1*/ public class Decaf extends Drink { public Decaf() { super.setDescription("Decaf"); super.setPrice(3); //3块钱 } @Override public double cost() { return getPrice();//super.getPrice()//这个就是父类的价格(自己什么也没加 (没有被装饰)) } // 重写getter 后面加上自己的花费 @Override public String getDescription() { return super.getDescription() + "-" + cost(); } } /** ConcreteComponent 2 * 也可以在ConcreteComponent和Drink类有一个过渡的类) (比如Coffee类) */ public class Espresso extends Drink { public Espresso(){ super.setDescription("Espresso"); super.setPrice(4); } @Override public double cost() { return getPrice();//super.getPrice()//这个就是父类的价格(自己什么也没加) } @Override public String getDescription() { return super.getDescription() + "-" + cost(); } }
下面看decorator
下的三个类:
第一个是装饰者的超类,继承自Drink
类:
public class Decorator extends Drink{ /** * 这个引用很重要,可以是单品,也可以是被包装过的类型,所以使用的是超类的对象 * 这个就是要被包装的单品(被装饰的对象) */ private Drink drink; //这里要拿到父类的引用,因为要控制另一个分支(具体的组件) public Decorator(Drink drink) { this.drink = drink; } /** * 如果drink是已经被装包过的,那么就会产生递归调用 最终到单品 */ @Override public double cost() { return super.getPrice() + drink.cost(); // 自己的价格和被包装单品的价格 } @Override public String getDescription() { return super.getDescription() + "-" + super.getPrice() + " && " + drink.getDescription(); } }
然后是两个装饰者:
/** * 这个是具体的装饰者() --> 继承自中间的装饰着Decorator */ public class Chocolate extends Decorator{ public Chocolate(Drink drink) { //如果父类搞了一个 带参数的构造函数,子类必须显示的使用super调用 super(drink); super.setDescription("Chocolate"); super.setPrice(1); } } public class Milk extends Decorator{ public Milk(Drink drink) { super(drink); //调用父类的构造函数 super.setDescription("Milk"); super.setPrice(3); } }
测试类:
public class MyTest { public static void main(String[] args) { //只点一个单品 (Decaf 咖啡) Drink order = new Decaf(); System.out.println("order description : " + order.getDescription()); System.out.println("order price : " + order.cost()); System.out.println("---------------加了调料的----------------"); order = new Milk(order);// 加了牛奶 order = new Chocolate(order); order = new Chocolate(order); // 加了两个巧克力 System.out.println("order description : " + order.getDescription()); System.out.println("order price : " + order.cost()); } }
程序输出:
order description : Decaf-3.0 order price : 3.0 ---------------加了调料的---------------- order description : Chocolate-1.0 && Chocolate-1.0 && Milk-3.0 && Decaf-3.0 order price : 8.0
2、JavaIO中使用装饰者模式
由于Java I/O库需要很多性能的各种组合,如果这些性能都是用继承的方法实现的,那么每一种组合都需要一个类,这样就会造成大量性能重复的类出现,所以Java IO使用的是装饰者设计模式。
所以我们可以定义自己的装饰者。
这里我们定义一个流,这个流将读入的小写字母转换成大写字母。
UpperCaseInputStream
代码如下:
/** * 自己定义的输入流 * 扩展FilterInputStream(这个类就是我们的Decorator) 中间装饰者 * 所以我们只要继承这个就可以扩展自己的输入流装饰者 */ public class UpperCaseInputStream extends FilterInputStream{ protected UpperCaseInputStream(InputStream in) { //这个InputStream就是我们的Drink 类(超类) super(in); } // 实现两个read()方法,将大写转化成小写的读入 //重写 相当于cost和description @Override public int read() throws IOException { int index = super.read(); //读取一个字节 return index == -1 ? index : Character.toUpperCase((char)(index)); //小写转换成大写 } //字节数组 @Override public int read(byte[] b, int off, int len) throws IOException { int index = super.read(b, off, len); for(int i = 0; i < index; i++) b[i] = (byte)Character.toUpperCase((char)(b[i])); return index; } }
测试一下使用这个类:
public class MyTest { public static void main(String[] args) throws IOException { InputStream in = new UpperCaseInputStream(new BufferedInputStream(new FileInputStream("/home/zxzxin/Java_Maven/DesignPatterns/src/main/java/decorator/java/in.txt")));// 将这个in.txt文件读入的内容转换成大写 int len; while((len = in.read()) >= 0) System.out.print((char)(len)); in.close(); } }
The output presentation:
IV Summary
Advantages and disadvantages:
Advantages : decoration and a decoration can be developed independently, not coupled to each other, a decorative pattern is inherited alternative model, a decorative pattern can be dynamically extended to achieve functional classes.
Drawback : multilayer decorative complex.
Practice: In most cases, a schematic example of an implementation of the decorative pattern to be simpler than the above given.
If only one class ConcreteComponent, consider removing abstract Component class (interface), the Decorator ConcreteComponent as a subclass;
If only one ConcreteDecorator class, then there is no need for a separate Decorator class, and can merge Decorator and ConcreteDecorator responsibility as a class.
Free Java needs its own advanced data collection, covering Java, Redis, MongoDB, MySQL, Zookeeper, Spring Cloud, Dubbo distributed high concurrency and other tutorials, a total of 30G.
Portal: HTTPS: // mp.weixin.qq.com/s/Jzdd fH-7yNudmkjT0IRL8Q