Java设计模式之装饰者模式
要实现装饰者模式,注意一下几点内容:
1.装饰者类要实现真实类同样的接口
2.装饰者类内有一个真实对象的引用(可以通过装饰者类的构造器传入)
3.装饰类对象在主类中接受请求,将请求发送给真实的对象(相当于已经将引用传递到了装饰类的真实对象)
4.装饰者可以在传入真实对象后,增加一些附加功能(因为装饰对象和真实对象都有同样的方法,装饰对象可以添加一定操作在调用真实对象的方法,或者先调用真实对象的方法,再添加自己的方法)
5.不用继承
先用实例说话,最后再具体装饰者模式
假设要制造添加甜蜜素和着色剂的面包:
1.需要生产一个正常面包
2.为节省成本(不使用玉米面),使用染色剂加入到正常面包中
3.和面,最后生产出染色面包
/**
* <p>实现做面包的接口</p>
* @author zhaoyx 2017年3月13日
* @version 1.0
* <p>注意事项: </p>
*/
public interface IBread {
/**
* <p>准备工作</p>
* @author zhaoyx 2017年3月13日
*/
public void prepair();
/**
* <p>和面</p>
* @author zhaoyx 2017年3月13日
*/
public void kneadFlour();
/**
* <p>烤面包</p>
* @author zhaoyx 2017年3月13日
*/
public void bake();
/**
* <p>制作流程</p>
* @author zhaoyx 2017年3月13日
*/
public void process();
}
/**
* <p>定义制作面包的抽象类</p>
* @author zhaoyx 2017年3月13日
* @version 1.0
* <p>
* 注意事项:
* 抽象类实现了IBread这个制作面包的接口,同时包含IBread接口的实例
* 装饰者类内有一个真实对象的引用
* </p>
*/
public abstract class AbstractBread implements IBread {
private final IBread bread;
public AbstractBread(IBread bread) {
super();
this.bread = bread;
}
@Override
public void prepair() {
this.bread.prepair();
}
@Override
public void kneadFlour() {
this.bread.kneadFlour();
}
@Override
public void bake() {
this.bread.bake();
}
@Override
public void process() {
prepair();
kneadFlour();
bake();
}
}
/**
* <p>制作正常面包</p>
* @author zhaoyx 2017年3月13日
* @version 1.0
* <p>注意事项: </p>
*/
public class NormalBread implements IBread {
@Override
public void prepair() {
System.out.println("准备面粉,水以及发酵粉...");
}
@Override
public void kneadFlour() {
System.out.println("和面...");
}
@Override
public void bake() {
System.out.println("烤面包...香喷喷的面包出炉了");
}
@Override
public void process() {
prepair();
kneadFlour();
bake();
}
}
public class SugarfreeDecorator extends AbstractBread{
public SugarfreeDecorator(IBread bread) {
super(bread);
}
public void paint(){
System.out.println("不加糖...");
}
public void kneadFlour(){
//不添加糖直接和面
this.paint();
super.kneadFlour();
}
}
/**
* <p>生产有甜蜜素的"面包"</p>
* @author zhaoyx 2017年3月13日
* @version 1.0
* <p>
* 注意事项:
* 和生产有着色剂的面包步骤一样
* </p>
*/
public class SweetDecorator extends AbstractBread {
public SweetDecorator(IBread bread) {
super(bread);
}
public void paint(){
System.out.println("添加甜蜜素...");
}
public void kneadFlour() {
//添加甜蜜素后和面
this.paint();
super.kneadFlour();
}
}
/**
* <p>生产有着色剂的"面包"</p>
* @author zhaoyx 2017年3月13日
* @version 1.0
* <p>
* 注意事项:
* 继承AbstarctBread类,所以可以有选择的覆盖正常生产面包的方法,并添加原有方法原来的信息,
* 同时也可以添加自己的方法,装饰者模式中这里最关键。
* 装饰者类要实现真实类同样的接口。
* </p>
*/
public class CornDecorator extends AbstractBread {
public CornDecorator(IBread bread) {
super(bread);
}
public void paint(){
System.out.println("添加柠檬黄的着色剂...");
}
public void kneadFlour(){
//添加着色剂后和面
this.paint();
super.kneadFlour();
}
}
public class testDecorator {
public static void main(String[] args) {
System.out.println("=======装饰面包开始");
IBread normalBread = new NormalBread();
// 加甜蜜素
//normalBread = new SweetDecorator(normalBread);
// 不加糖
normalBread = new SugarfreeDecorator(normalBread);
normalBread = new CornDecorator(normalBread);
normalBread.process();
System.out.println("=======装饰面包结束");
}
}
装饰者模式使用,我的个人总结:
1.首先创建一个接口,里面包含整个业务所需的方法。
2.创建一个包含整个业务的正常类用来实现刚才创建的接口,并用其中一个接口把其它接口串联起来。
3.创建一个抽象类,实现刚才创建的接口,并创建接口的实例,在覆盖的接口中用刚才创建的实例调用对应的接口。
4.创建具体的装饰类并继承刚才创建的抽象类,在该装饰类中添加要增加的业务,覆盖要覆盖的父类方法
5.在客户端,用接口创建刚才正常类的对象,再把这个对象用装饰类进行装饰,最后用这个对象调用正常类中刚才把其它接口串联起来的那个
接口。
装饰者模式在项目中使用总结:
把方法写在了service接口中,用具体的类实现这个接口,在实现类对应的方法里把要添加的业务和其他的业务
进行整合,这有点类似一个简单的装饰者模式。