Android 设计模式 - 装饰器模式

作者: Android架构 | 来源:发表于2019-03-01 21:33 被阅读6次

    简介

    在现实生活中可以看到很多装饰模式的例子,或者可以大胆的说装饰模式无处不在,就拿人来说,人需要各式各样的衣着,不管你穿着怎样,但是对于人的本质来说是不变的,充其量只是在外面披上一层遮羞物而已,这就是装饰模式,装饰物各不相同但是对象的本质是不变的.它的uml类图如下:

    装饰模式的简单实现

    人总是要穿衣服,我们将人定义为一个抽象类,将其穿衣服的行为定义为一个抽象方法,show me the code.

    public abstract class Person {
        /**
         * person下有一个穿着的抽象方法
         */
        public abstract void dressed();
    }
    
    
    public class Boy extends Person{
        @Override
        public void dressed() {
            System.out.println("穿了内衣内裤");
        }
    }
    
    

    PersonCloth用来装饰Person

    public abstract class PersonCloth extends Person{
    
        protected Person mPerson;   //保持一个Person类的引用
    
        public PersonCloth(Person person) {
            mPerson = person;
        }
    
        @Override
        public void dressed() {
            mPerson.dressed();
        }
    }
    
    

    下面两个是继承PersonCloth的实际装饰类

    public class CheapCloth extends PersonCloth{
        public CheapCloth(Person person) {
            super(person);
        }
    
        public void dressShorts(){
            System.out.println("穿条短裤");
        }
    
        @Override
        public void dressed() {
            super.dressed();
        }
    }
    
    
    public class ExpensiveCloth extends PersonCloth{
        public ExpensiveCloth(Person person) {
            super(person);
        }
    
        /**
         * 穿短袖
         */
        private void dressShirt(){
            System.out.println("穿件短袖");
        }
    
        /**
         * 穿皮衣
         */
        private void dressLeather(){
            System.out.println("穿件皮衣");
        }
    
        /**
         * 穿牛仔裤
         */
        private void dressJean(){
            System.out.println("穿条牛仔裤");
        }
    
        @Override
        public void dressed() {
            super.dressed();
            dressShirt();
            dressLeather();
            dressJean();
        }
    }
    
    

    最终调用

    public class Main {
        public static void main(String[] args){
            //首先我们要有一个Boy
            Person person = new Boy();
    
            //穿上便宜的衣服
            CheapCloth cheapCloth = new CheapCloth(person);
            cheapCloth.dressed();
    
            //穿上昂贵的衣服
            ExpensiveCloth expensiveCloth = new ExpensiveCloth(person);
            expensiveCloth.dressed();
        }
    }
    
    

    Android源码中的装饰模式

    在Android中Context常常被称为上帝对象,Context中定义了大量的抽象方法,如下

    //....代码省略...
    public abstract void startActivity(@RequiresPermission Intent intent);
    public abstract void startActivity(@RequiresPermission Intent intent,
                @Nullable Bundle options);
    //....代码省略...
    
    

    而Context的真正实现其实是在ContextImpl中完成,ContextImpl继承自Context抽象类,并实现了Context的抽象方法.

    class ContextImpl extends Context {
    //....代码省略...
     @Override
        public void startActivity(Intent intent) {
            warnIfCallingFromSystemProcess();
            startActivity(intent, null);
        }
    @Override
        public void startActivity(Intent intent, Bundle options) {
            warnIfCallingFromSystemProcess();
    
            // Calling start activity from outside an activity without FLAG_ACTIVITY_NEW_TASK is
            // generally not allowed, except if the caller specifies the task id the activity should
            // be launched in.
            if ((intent.getFlags()&Intent.FLAG_ACTIVITY_NEW_TASK) == 0
                    && options != null && ActivityOptions.fromBundle(options).getLaunchTaskId() == -1) {
                throw new AndroidRuntimeException(
                        "Calling startActivity() from outside of an Activity "
                        + " context requires the FLAG_ACTIVITY_NEW_TASK flag."
                        + " Is this really what you want?");
            }
            mMainThread.getInstrumentation().execStartActivity(
                    getOuterContext(), mMainThread.getApplicationThread(), null,
                    (Activity) null, intent, -1, options);
        }
    //....代码省略...
    }
    
    

    ContextImpl其实承担的是组件的身份,那么谁来承担装饰者的身份呢,其实只要继承自ContextThemeWrapper的组件都是装饰者的身份,例如Activity.

    public class Activity extends ContextThemeWrapper
    
    

    ContextThemeWrapper又继承ContextWrapper

    public class ContextWrapper extends Context {
        Context mBase;
    
        public ContextWrapper(Context base) {
            mBase = base;
        }
    }
    
    

    其实看到这里已经可以看到一些装饰者模式了,ContextWrapper的startActivity其实就是调用的mBase,而mBase实际上就是ContextImpl的实例.

    @Override
        public void startActivity(Intent intent) {
            mBase.startActivity(intent);
        }
    
    

    总结

    装饰模式常常会和代理模式混淆,我们来说说这两者的区别,装饰模式是对对象功能的扩展,是继承关系的一种替代方案(比继承更加灵活),而代理模式则是给一个对象提供一个代理对象,并有代理对象来控制原有对象的引用。
    装饰模式应该为所有装饰的对象增强功能;代理模式对代理的对象施加控制,但不对对象本身的功能进行增强
    【附录】

    资料图

    需要资料的朋友可以加入Android架构交流QQ群聊:513088520

    点击链接加入群聊【Android移动架构总群】:加入群聊

    获取免费学习视频,学习大纲另外还有像高级UI、性能优化、架构师课程、NDK、混合式开发(ReactNative+Weex)等Android高阶开发资料免费分享。

    相关文章

      网友评论

        本文标题:Android 设计模式 - 装饰器模式

        本文链接:https://www.haomeiwen.com/subject/ohnjuqtx.html