设计模式之装饰器模式(Decorator Design Pattern)

装饰器模式是八种结构型模式之一,通过一个装饰类来包装原有的类,并在保持类方法签名完整性的前提下,提供了额外的功能。

装饰器模式与代理模式非常像,区别是代理模式是原始功能上附加功能,而装饰器模式是增强原始功能。

代理模式:我(代理)不是你(原始类),我只是代表你的(部分或全部)能力,不会改变你的能力;

装饰器模式:我(装饰器)就是你(原始类),我是你的伪装,不仅有你的全部能力,还可以改变你的能力;

装饰类有两个特点:完全包装原始类和层层包装

  • 要完全包装原始类,装饰类必须与原始类实现同一个接口,并实现相同的方法。装饰类通过组合原始类,在每个方法中调用原始类的方法。
//人类
interface HumanBeing {
  //速度
  public void velocity();
  //反应
  public void reaction();
  //视野
  public void vision();
}

//正常人
class Human implements HumanBeing {
    //速度
    public void velocity(){
        System.out.println("速度:每小时走10公里");
    }
    //反应
    public void reaction(){
        System.out.println("反应:打不到飞行中的蚊子");
    }
    //视野
    public void vision(){
        System.out.println("视野:可看到10公里外事物");
    }
}


//钢铁侠,普通人穿上的钢铁服
class IronMan implements HumanBeing {

    HumanBeing human;
  
    public IronMan(HumanBeing human) {
        System.out.println("--变身钢铁侠------------");
        this.human = human;
    }

    //速度
    public void velocity(){
        this.human.velocity();
        System.out.println("速度:时速加上500公里,会飞了");
    }
    //反应
    public void reaction(){
        this.human.reaction();
        System.out.println("反应:变快100倍,可以接住子弹");
    }
    //视野
    public void vision(){
        this.human.vision();
        System.out.println("视野:视野增加到了30公里,同时看到多个目标");
    }
}


//圣斗士,普通人穿上的圣衣
class holyWarriors implements HumanBeing {

    HumanBeing human;
  
    public holyWarriors(HumanBeing human) {
        System.out.println("--变身圣斗士------------");
        this.human = human;
    }

    //速度
    public void velocity(){
        this.human.velocity();
        System.out.println("速度:时速加上200公里");
    }
    //反应
    public void reaction(){
        this.human.reaction();
        System.out.println("反应:变快1000倍,可以削掉飞行中蚊子的翅膀");
    }
    //视野
    public void vision(){
        this.human.vision();
        System.out.println("视野:视野添加了50公里");
    }
}

public class Demo {
    public static void main(String[] args) {
        HumanBeing human= new Human();
        //变身钢铁侠
        physicalExamination(new IronMan(human));
        //变身圣斗士
        physicalExamination(new holyWarriors(human));
    }

    //体检
    private static void physicalExamination(HumanBeing human){
        human.velocity();
        human.reaction();
        human.vision();
    }
}

//执行结果
--变身钢铁侠------------
速度:每小时走10公里
速度:时速加上500公里,会飞了
反应:打不到飞行中的蚊子
反应:变快100倍,可以接住子弹
视野:可看到10公里外事物
视野:视野增加到了30公里,同时看到多个目标
--变身圣斗士------------
速度:每小时走10公里
速度:时速加上200公里
反应:打不到飞行中的蚊子
反应:变快1000倍,可以削掉飞行中蚊子的翅膀
视野:可看到10公里外事物
视野:视野添加了50公里

通过IronMan、holyWarriors 两个类包装,对正常人的能力进行了增强。

  • 装饰类还有一个特点,就是可以层层包装。
public class Demo {
    public static void main(String[] args) {
        HumanBeing human= new Human();
        //变身钢铁侠之后又变身圣斗士,普通人有了钢铁侠和圣斗士的能力
        physicalExamination(new holyWarriors(new IronMan(human)));
    }

    //体检
    private static void physicalExamination(HumanBeing human){
        human.velocity();
        human.reaction();
        human.vision();
    }
}

//执行结果
--变身钢铁侠------------
--变身圣斗士------------
速度:每小时走10公里
速度:时速加上500公里,会飞了
速度:时速加上200公里
反应:打不到飞行中的蚊子
反应:变快100倍,可以接住子弹
反应:变快1000倍,可以削掉飞行中蚊子的翅膀
视野:可看到10公里外事物
视野:视野增加到了30公里,同时看到多个目标
视野:视野添加了50公里

 装饰类之间可以进行随意层层包装,代码也能正常运行。

类图: 

装饰模式在实际使用中每一个装饰类都需要完全包装原始类,但并不是每个方法(能力)都会改变。如果每个装饰类都要去实现调用原始类的方法,显然这不符合KISS、DRY原则。所以会让装饰类继承一个抽象装饰类,由这个抽象装饰类调用原始类的方法。真正的装饰类重写需要改变能力的方法。现在我们把人类增加一种能力“变形”,看怎么使用抽象装饰类。

//人类
public interface HumanBeing {
    //速度
    public void velocity();
    //反应
    public void reaction();
    //视野
    public void vision();
    
    //变形
    public void deformation();
}


//正常人
public class Human implements HumanBeing {
    //速度
    public void velocity(){
        System.out.println("速度:每小时走10公里");
    }
    //反应
    public void reaction(){
        System.out.println("反应:打不到飞行中的蚊子");
    }
    //视野
    public void vision(){
        System.out.println("视野:可看到10公里外事物");
    }

    //变形
    public void deformation(){
        System.out.println("变形:不能变形");
    }
}

//抽象装饰类:超人
public abstract class Superman implements HumanBeing {
    HumanBeing human;

    public Superman(HumanBeing human) {
        this.human = human;
    }

    //速度
    public void velocity(){
        this.human.velocity();
    }
    //反应
    public void reaction(){
        this.human.reaction();
    }
    //视野
    public void vision(){
        this.human.vision();
    }

    //变形
    public void deformation(){
        this.human.deformation();
    }
}


//钢铁侠,继承超人
public class IronMan extends Superman {

    public IronMan(HumanBeing human) {
        super(human);
        System.out.println("--变身钢铁侠------------");
    }

    //重写速度
    public void velocity(){
        super.velocity();
        System.out.println("速度:时速加上500公里,会飞了");
    }
    //重写反应
    public void reaction(){
        super.reaction();
        System.out.println("反应:变快100倍,可以接住子弹");
    }
    //重写视野
    public void vision(){
        super.vision();
        System.out.println("视野:视野增加到了30公里,同时看到多个目标");
    }

    //没有变形能力,所有不需要重写变形

}

//圣斗士,继承超人
public class holyWarriors extends Superman {

    public holyWarriors(HumanBeing human) {
        super(human);
        System.out.println("--变身圣斗士------------");
    }

    //重写速度
    public void velocity(){
        super.velocity();
        System.out.println("速度:时速加上200公里");
    }
    //重写反应
    public void reaction(){
        super.reaction();
        System.out.println("反应:变快1000倍,可以削掉飞行中蚊子的翅膀");
    }
    //重写视野
    public void vision(){
        super.vision();
        System.out.println("视野:视野添加了50公里");
    }

    //没有变形能力,所有不需要重写
}

//橡胶人,继承超人
public class RubberMan extends Superman {

    public RubberMan(HumanBeing human) {
        super(human);
        System.out.println("--变身橡胶人------------");
    }

    //速度没有变化,所有不需要重写
    //反应没有变化,所有不需要重写
    //视野没有变化,所有不需要重写

    //变形
    public void deformation(){
        super.deformation();
        System.out.println("变形:可以变长");
    }
}

类图: 

装饰模式运用的是多用组合少用继承的设计思想,实际装饰类通过继承也可以实现,但要达到随意层层包装的效果将导致继承爆炸。

装饰类的运用比较多,比较有代表性的是java.io类库:

 

  • 2
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值