标准 专业
多元 极客

设计模式研究院(1)——装饰模式

什么是装饰模式?

装饰模式是一种对象结构型模式。

装饰模式可以动态地为一个对象增加一些额外的行为。

装饰模式可以在不改变一个对象本身功能的基础上,提供给对象额外的实现。不同于继承在编译时为类增加额外的实现,装饰模式在运行时为对象提供了额外的实现。装饰模式无需子类即可为对象动态添加额外的实现,用关联关系代替了继承关系。

比如生活中,我们买到的毛坯房,基本功能就是可以住,有水有电有网,但是我们通常不会这样就搬进去住,我们还要对其进行个性化装修,让其增加做饭、睡觉和休息等功能,但是有水优点有网这些基本功能还是存在的,这其实就是装饰模式。

核心结构

  • Component,抽象构件,是具体构件和抽象装饰的共同父类,声明了在具体构件中需要实现的业务执行,。
  • ConcreteComponent,具体构件,是抽象构件的子类,实现抽象构件中声明的业务执行。
  • Decorator,抽象装饰,是抽象构件的子类,用于给具体构件增加职责,并声明具体装饰中需要实现的业务执行,它维护了一个抽象构件的引用,在必要时通过这个引用实现装饰的目的。
  • ConcreteComponent,具体装饰,是抽象装饰的子类,具体实现了抽象装饰中声明的装饰职责。

类图展示

装饰模式

代码分析

推送功能对于用户来说,可能就是推推消息,很讨厌。其实,推送还有一个功能就是及时解决线上问题,也就是push一段hotfix代码过去。

在这里,我们依然举推送中的实例来实现装饰模式。

首先我们定义推送主题——抽象构件:

/**
 * Created by <sunshine> mysunshinedreams@163.com on 2017/1/20 0020.
 * 装饰模式——抽象构件
 */
public abstract class Push {
    public abstract void send();
}

有了抽象构件,接下来我们就需要实现具体构件——指定推送:

/**
 * Created by <sunshine> mysunshinedreams@163.com on 2017/1/20 0020.
 * 装饰模式——具体构件
 */
public class AppointPush extends Push {
    @Override
    public void send() {
        System.out.println("appoint push task");
    }
}

全量推送:

/**
 * Created by <sunshine> mysunshinedreams@163.com on 2017/1/20 0020.
 * 装饰模式——具体构件
 */
public class FullAmountPush extends Push {
    @Override
    public void send() {
        System.out.println("full amount push task");
    }
}

在核心结构中我们讲过,抽象装饰也需要实现抽象构件,所以接下来我们需要定义抽象装饰——消息:

/**
 * Created by <sunshine> mysunshinedreams@163.com on 2017/1/20 0020.
 * 装饰模式——抽象装饰
 */
public abstract class Message extends Push {
    private Push push;
    public Message(Push push) {
        this.push = push;
    }
    @Override
    public void send() {
        push.send();
    }
}

接下来就需要针对抽象装饰,实现一些具体的装饰职责。

透传消息类型:

/**
 * Created by <sunshine> mysunshinedreams@163.com on 2017/1/20 0020.
 * 装饰模式——具体装饰
 */
public class MessageMessage extends Message {
    public MessageMessage(Push push) {
        super(push);
    }
    @Override
    public void send() {
        this.setMessageMessage();
        super.send();
    }
    private void setMessageMessage() {
        System.out.println("append title to message's body");
        System.out.println("append content to message's body");
    }
}

通知消息类型:

/**
 * Created by <sunshine> mysunshinedreams@163.com on 2017/1/20 0020.
 * 装饰模式——具体装饰
 */
public class NotificationMessage extends Message {
    public NotificationMessage(Push push) {
        super(push);
    }
    @Override
    public void send() {
        this.setNotificationMessage();
        super.send();
    }
    private void setNotificationMessage() {
        System.out.println("append title to notification's body");
        System.out.println("append content to notification's body");
    }
}

这样,一个简单的装饰模式就已经实现了,接下来上测试代码:

/**
 * Created by <sunshine> mysunshinedreams@163.com on 2017/1/20 0020.
 * 装饰模式测试
 */
public class DecoratorTest {
    public static void main(String[] args) {
        decoratorTest();
    }
    private static void decoratorTest() {
        try {
            Message notificationMessage = new NotificationMessage(new FullAmountPush());
            notificationMessage.send();
            Message messageMessage = new MessageMessage(new FullAmountPush());
            messageMessage.send();
            notificationMessage = new NotificationMessage(new AppointPush());
            notificationMessage.send();
            messageMessage = new MessageMessage(new AppointPush());
            messageMessage.send();
        } catch (Exception e) {
            e.printStackTrace();
        }
     }
}

模式总结

优点

  • 对比于继承扩展,装饰模式避免了类的指数级剧增。
  • 可以对对象进行多层装饰,实现更丰富的行为。
  • 符合开闭原则,在更新对象的表现行为时,可以新增、变换装饰方式,而无需改变现有代码。

缺点

  • 装饰模式虽然有更好的灵活性,但同时增加的系统的设计难度和维护难度。
  • 使用装饰模式对对象进行装饰时,势必会产生多个用于装饰对象,如果一个系统中具体装饰类过多,可能会影响系统GC,在一定程度上影响了系统的性能。

适用场景

  • 在不影响其他对象的情况下,透明、动态地给单个对象添加职责。
  • 在不能够或者不适合使用继承的方式扩展类时,可以采用装饰模式。比如说用final修饰的类,或者继承类时需要爆炸添加多个子类。

 

赞(2) 投币

评论 抢沙发

慕勋的实验室慕勋的研究院

码字不容易,路过请投币

支付宝扫一扫

微信扫一扫