Java设计模式之装饰者模式——代码里的故事——

装饰者模式


引入:

 装饰者模式,从字面上一看就能很容易联想到这是用来装饰扩展一个类的,可以使扩展一个类具有某些属性和功能(方法),
 那么,就有人会说了,扩展一个类,我在写一个子类继承于它,然后在扩展对应的属性或者功能不就行了,为什么要用装饰者模式呢?难道他有什么独特的地方吗?
带着这个疑问,接下来就让我们去看看装饰者模式到底是怎样一回事呢?
 现在我们有一场戏需要拍一下,在一个浪漫的咖啡厅里,我们的女主人公和男主人公出现了(烂大街的剧情),接下来会有什么故事呢?别急,我们得用程序猿一族的交流方式来表达它:
我们来看下代码的实现:

下面是一场一镜:

这里写图片描述

//首先定义了一个抽象的Person类,男主和女主都该类的具体实现
public abstract class Person {
    abstract void look();
}
//女主
public class Girl extends Person{
    @Override
    void look() {
      //nothing to do
    }
}
//男主
public class Lad extends Person{
    @Override
    void look() {
      //nothing to do
    }
}
//两人就这样见面了,没有任何打扮,都略显邋遢,那么,接下来还会有故事吗? maybe not
public class CoffeeHouse {

    private Girl mGirl;
    private Lad mLad;

    public CoffeeHouse() {
        mGirl = new Girl();
        mLad = new Lad();
        mGirl.look();
        mLad.look();
    }
}

 也许都应该稍微打扮一下,毕竟第一眼的印象还是很重要的。那么将如何做呢?通常我们在通过一个继承Girl、Lad的子类,
重写父类的look()方法就可以了,让我们来看一下如何实现?

一场二镜:

在一镜的基础上我们做一点小的修改,如下:
这里写图片描述

//装扮后的女主
public class BeautifulGirl extends Girl{
    @Override
    void look() {
        //装扮一番
        dressUp();
        makeUp();
        hairUp();
        super.look();
    }

    private void dressUp() {
        //选一套漂亮的衣服
        System.out.println("白色连衣裙");
    }

    private void makeUp() {
        System.out.println("化一个淡妆");
    }

    private void hairUp() {
        System.out.println("长发披肩,空气刘海");
    }
}
//男主也可以简单打扮一番
public class Gentleman extends Lad {
    @Override
    void look() {
        dressUp();
        hairUp();
        super.look();
    }

    private void dressUp() {
        System.out.println("一身帅气的西装");
    }

    private void hairUp() {
        System.out.println("最帅的发型");
    }
}
//咖啡屋里出现的是精心打扮的男主和女主了
public class CoffeeHouse {

    private Girl mGirl;
    private Lad mLad;

    public CoffeeHouse() {
        mGirl = new BeautifulGirl();
        mLad = new Gentleman();
        mGirl.look();
        mLad.look();
    }
}
//看看是不是和之前不一样了呢
public class Client {
    public static void main(String args[]) {
      CoffeeHouse coffeeHouse = new CoffeeHouse();
    }
}

 如上展示的,我们通过继承的方式,对起初的男主和女主两个类做了扩充,是的我们已经完成了类的扩充,但是还没有谈到装饰者模式,既然我们都实现需求了,还有用装饰者的必要吗?别急我们接着往下看。
 如果在上面的基础上,突然我们的编剧说,女主还得染个指甲,男主再带块名贵的手表,又或者说我们的女主很任性打扮的顺序得调整一下。
这个时候怎么办呢?有人会说了,这个好办啊,把Gentleman、BeautifulGirl类按要求修改一下不就完了么。是的,但是如果剧本不停的改来改去,不停的变,你还愿意不断的去修改吗?你们确定你的修改不会引出什么未知的问题吗。
这种做法并不符合开闭原则(对扩展开发,对修改关闭,变化用扩展来实现,而不是去修改已有的代码)。那要如何做呢?我们接着往下走。


一场三镜:

 我们把之前的方式pass掉,重新做一下调整:
在该场景下,我们不在通过继承去Girl、Lad类实现去他们的扩展,而是引入了一个新的抽象类Conmetician(化妆师),
Conmetician类的构造方法传入了一个参数Person类,可见应该是对传入的Person对象做相关的操作。而不同的扩展可以通过不同的Conmetician实现类来完成,不需要去修改类Girl和Lad。具体看如下代码部分:
这里写图片描述

//和之前一致,最初的三个类
public abstract class Person {
    abstract void look();
}

public class Girl extends Person{
    @Override
    void look() {

    }
}

public class Lad extends Person{
    @Override
    void look() {

    }
}
//新增的抽象化妆师类
public abstract class Cosmetician extends Person{
    private Person mSomeone;
    public Cosmetician(Person someOne) {
        this.mSomeone = someOne;
    }

    @Override
    void look() {
        this.mSomeone.look();
    }
}
//如下三个类分别继承于Cosmetician,同时扩展完成了各自需要处理的工作
public class ClothCosmetician extends Cosmetician{
    public ClothCosmetician(Person someOne) {
        super(someOne);
    }

    @Override
    void look() {
        dressUp();
        super.look();
    }

    private void dressUp() {
        System.out.println("盛装打扮");
    }
}

public class HairCosmetician extends Cosmetician{
    public HairCosmetician(Person someOne) {
        super(someOne);
    }

    @Override
    void look() {
        hairUp();
        super.look();
    }

    private void hairUp() {
        System.out.println("发型打扮");
    }
}

public class FaceCosmetician extends Cosmetician{
    public FaceCosmetician(Person someOne) {
        super(someOne);
    }

    @Override
    void look() {
        faceUp();
        super.look();
    }

    private void faceUp() {
        System.out.println("面部打扮");
    }
}
//现在需要布置一下开拍的准备工作,看看如何布置的
public class CoffeeHouse {

    private Girl mGirl;
    private Lad mLad;

    public CoffeeHouse() {
        /*这里我们对Girl进行了装扮,现在能清晰的看到,如果我们想添加新的扩展就不在需要去
        * 修改对应的对象类,只需要在实现一个Cosmetician具体的功能类就能完成扩展,
        * 可以看到,如果要调整扩展的顺序也是很方便的,只需修改对应的场景类,是不是更加易于扩展了?符合开闭原则
        */
        mGirl = new Girl();
        mLad = new Lad();
        HairCosmetician hairCosmetician = new HairCosmetician(mGirl);
        ClothCosmetician clothCosmetician = new ClothCosmetician(mGirl);
        FaceCosmetician faceCosmetician = new FaceCosmetician(mGirl);
        mGirl.look();
        mLad.look();
    }
}

到这里,装饰者模式的实现就完成了,怎么样?很简单吧!下面我们在来回顾一下,做个总结吧

装饰者模式:动态的给一个对象添加额外的指责,相对于生成子类的继承方式更加的灵活,易于扩展.

如下是对应的UML图:
这里写图片描述
Component(零件):抽象类或者接口,原始的核心对象
ConcreteComponent:具体构件(被装饰的对象)
Decorator:装饰角色:一般为抽象类,内部必须有一个private的Component变量,这是它需要装饰的对象.
下面简单总结下代码的实现过程:

public abstract class Component {
    abstract void operation();
}

public abstract class Decorator extends Component {
    private Component mComponent;
    public Decorator(Component component) {
        this.mComponent = component;
    }

    @Override
    void operation() {
        mComponent.operation();
    }
}

public class ConcreteComponent extends Component {
    @Override
    void operation() {
        //原始的基本的一些操作
    }
}

public class ConcreteDecorator extends Decorator {
    public ConcreteDecorator(Component component) {
        super(component);
    }

    @Override
    void operation() {
        extendOperation();
        super.operation();
    }

    private void extendOperation() {
        //装饰类需要完成的扩展工作
    }
}

public class Client{
    public static void main(String[] args) {
        Component component = new ConcreteComponent();
        component = new ConcreteDecorator(component);
        component.operation();
    }
}

 继承---->静态增加类的功能
 装饰---->动态增加类的功能
 优点:
 装饰者与被装饰者相互独立,无依赖,易于扩展.
 继承关系的一种替代方案.
 可以实现动态扩展实现类的功能.
 缺点:多层的装饰是很复杂的,应避免过多的装饰类,想象一下,你收到一个礼物,拆开盒子里面还是盒子…你会有何感受
 使用场景:
 需要给一个类动态的增加,撤销功能.
 为一批兄弟类改装或加装功能.

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值