android设计模式之装饰模式

装饰模式(Decorator Pattern)也称为包装模式(Wrapper Pattern),结构型设计模式之一,其使用一种对客户端透明的方式来动态扩展对象的功能,同时它也是继承关系的一种替代方案之一。(组合方案也是继承关系的一种替代方案)。

 

装饰模式的定义

动态给一个对象添加一些额外的职责。就增加功能来说,装饰模式生成子类更加灵活。

 

装饰模式的使用场景

需要透明且动态地扩展类的功能时。

 

装饰模式的UML类图

角色介绍

Component:抽象组件

可以是一个接口或者抽象类,其充当被装饰的原始对象。

ConcreteComponent:组件具体实现类

该类是Component类基本实现,也是我们装饰的具体对象。

Decorator:抽象装饰者

顾名思义,其承担的职责就是为了装饰我们的组件对象,其内部一定要有一个指向组件对象的引用。在大多数情况下,该类为抽象类,需要根据不同的装饰逻辑实现不同的子类。当然,如果装饰逻辑单一,只有一个的情况下我们可以省略该类直接作为具体的装饰者。

 

ConcreteDecoratorA:装饰者具体实现类

只是对抽象装饰者作出具体的实现。

 

ConcreteDecoratorB:同上。

同上。

Client:客户类。

 

D:\Users\user\ProjectThree\DecoratorPatternDemo\app\src\main\java\decoratorpattern\gome\com\decoratorpatterndemo\Component.java

public abstract class Component {

    /**
     * 抽象方法
     * 可以添加更多抽象方法
     */
    public abstract void operate();
}


D:\Users\user\ProjectThree\DecoratorPatternDemo\app\src\main\java\decoratorpattern\gome\com\decoratorpatterndemo\ConcreteComponent.java

public class ConcreteComponent extends Component {
    @Override
    public void operate() {
        //实现具体逻辑
    }
}

D:\Users\user\ProjectThree\DecoratorPatternDemo\app\src\main\java\decoratorpattern\gome\com\decoratorpatterndemo\Decorator.java


public abstract class Decorator extends Component {

    private Component component;//持有一个Component对象的引用

    /**
     *必要的构造方法 需要一个Component类型的对象
     * @param component
     */
    public Decorator(Component component) {
        super();
        this.component = component;
    }

    @Override
    public void operate() {
        component.operate();
    }
}


D:\Users\user\ProjectThree\DecoratorPatternDemo\app\src\main\java\decoratorpattern\gome\com\decoratorpatterndemo\ConcreteDecoratorA.java

public class ConcreteDecoratorA extends Decorator {
    /**
     * 必要的构造方法 需要一个Component类型的对象
     *
     * @param component
     */
    public ConcreteDecoratorA(Component component) {
        super(component);
    }

    @Override
    public void operate() {
        //装饰方法A和B既可以在父类方法前调用也可在之后调用

 operateA();
        super.operate();
        operateB();
    }

    /**
     * 自定义的装饰方法 A
     */
    public void operateA() {
        //装饰方法逻辑......
    }

    /**
     * 自定义的装饰方法B
     */
    public void operateB() {
        //装饰方法逻辑......
    }
}


D:\Users\user\ProjectThree\DecoratorPatternDemo\app\src\main\java\decoratorpattern\gome\com\decoratorpatterndemo\MainActivity.java

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        //构造被装饰的组件对象
        Component component = new ConcreteComponent();

        //根据组件对象构造装饰者对象A并调用,此时相当于给组件对象增加装饰者A的功能方法
        Decorator decorator = new ConcreteDecoratorA(component);
        decorator.operate();
    }
}

装饰模式简单Demo

D:\Users\user\ProjectThree\DecoratorPatternDemo\app\src\main\java\decoratorpattern\gome\com\decoratorpatterndemo\Person.java


//我们将人定义为一个抽象类,将其穿衣服的行为定义为一个抽象方法
//该类就是上面我们所提到的抽象组件类,也就是我们需要装饰的原始对象
public abstract class Person {

    /**
     * Person 下有一个穿着的抽象方法
     */
    public abstract void dressed();
}

D:\Users\user\ProjectThree\DecoratorPatternDemo\app\src\main\java\decoratorpattern\gome\com\decoratorpatterndemo\Boy.java

//Boy类继承于Person类,该类仅对Person中的dressed方法做了具体的实现,
//而Boy类则是我们所要装饰的具体对象,现在需要一个装饰者类装饰我们这个Boy对象。
public class Boy extends Person {
    @Override
    public void dressed() {
        //Boy类下的dressed方法的基本逻辑
        Log.v(MainActivity.DecoratorTAG, "穿衣服");
    }
}

//PersonCloth类来表示人所穿的衣服
//在PersonCloth类中我们保持了一个对Person类的引用,可以方便地调用具体被装饰对象中的方法,
//这便是在不破坏原类层次结构的情况下增加一些功能
//我们只需要在被装饰对象的相应方法前或后增加相应的功能
//在装饰物只有一个的情况下,可不必声明一个抽象类作为装饰者抽象的提取,仅需要定义一个普通类表示装饰者即可。
public abstract class PersonCloth extends Person {

    protected Person mPerson;//保持一个Person类的引用

    public PersonCloth(Person person) {
        this.mPerson = person;
    }

    @Override
    public void dressed() {
        //调用Person类中的dressed方法
        mPerson.dressed();
    }
}



D:\Users\user\ProjectThree\DecoratorPatternDemo\app\src\main\java\decoratorpattern\gome\com\decoratorpatterndemo\CheapCloth.java


public class CheapCloth extends PersonCloth {
    public CheapCloth(Person person) {
        super(person);
    }

    public void dressShorts() {
        Log.v(MainActivity.DecoratorTAG, "穿短裤");
    }

    @Override
    public void dressed() {
        super.dressed();
        dressShorts();
    }
}

D:\Users\user\ProjectThree\DecoratorPatternDemo\app\src\main\java\decoratorpattern\gome\com\decoratorpatterndemo\ExpensiveCloth.java



public class ExpensiveCloth extends PersonCloth {
    public ExpensiveCloth(Person person) {
        super(person);
    }

    private void dressShirt() {
        Log.v(MainActivity.DecoratorTAG, "传短袖");
    }

    private void dressLeather() {
        Log.v(MainActivity.DecoratorTAG, "穿件皮衣");
    }

    private void dressJean() {
        Log.v(MainActivity.DecoratorTAG, "穿件牛仔裤");
    }

    @Override
    public void dressed() {
        super.dressed();
        dressShirt();
        dressLeather();
        dressJean();
    }
}

CheapCloth 与 ExpensiveCloth  都为原本Boy类中的dressed方法提供了功能扩展,不过这种扩展并非直接修改原有的方法逻辑或结构,更恰当的说,仅仅是在另一个类中将原本方法和新逻辑进行封装整合。

D:\Users\user\ProjectThree\DecoratorPatternDemo\app\src\main\java\decoratorpattern\gome\com\decoratorpatterndemo\MainActivity.java

public class MainActivity extends AppCompatActivity {

    public static final String DecoratorTAG = "decoratortag";
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        Person person = new Boy();

        PersonCloth clothCheap = new CheapCloth(person);
        clothCheap.dressed();

        PersonCloth clothExpensive = new ExpensiveCloth(person);
        clothExpensive.dressed();
    }
}

Log分析:

V/decoratortag: 穿衣服

V/decoratortag: 穿短裤

V/decoratortag: 穿衣服

V/decoratortag: 传短袖

V/decoratortag: 穿件皮衣

V/decoratortag: 穿件牛仔裤

 

 

Android源码中的装饰模式

Context类在android中经常使用,它本质上是一个抽象类,其在我们的装饰模式中相当于抽象组件,在其内部定义了大量的抽象方法。

startActivity方法

/**(有关应用程序环境的全局信息的接口。 这是一个抽象类,其实现由Android系统提供。)
 * Interface to global information about an application environment.  This is
 * an abstract class whose implementation is provided by
 * the Android system.  It
 * allows access to application-specific resources and classes, as well as
 * up-calls for application-level operations such as launching activities,
 * broadcasting and receiving intents, etc.
 */(它允许访问特定于应用程序的资源和类,以及对应用程序级操作的上调,例如启动活动,广播和接收意图等。)
public abstract class Context {

}

 /**
     * Launch a new activity.  You will not receive any information about when
     * the activity exits.
     *
     * <p>Note that if this method is being called from outside of an
     * {@link android.app.Activity} Context, then the Intent must include
     * the {@link Intent#FLAG_ACTIVITY_NEW_TASK} launch flag.  This is because,
     * without being started from an existing Activity, there is no existing
     * task in which to place the new activity and thus it needs to be placed
     * in its own separate task.
     *
     * <p>This method throws {@link ActivityNotFoundException}
     * if there was no Activity found to run the given Intent.
     *
     * @param intent The description of the activity to start.
     * @param options Additional options for how the Activity should be started.
     * May be null if there are no options.  See {@link android.app.ActivityOptions}
     * for how to build the Bundle supplied here; there are no supported definitions
     * for building it manually.
     *
     * @throws ActivityNotFoundException &nbsp;
     *
     * @see #startActivity(Intent)
     * @see PackageManager#resolveActivity
     */
    public abstract void startActivity(@RequiresPermission Intent intent,
            @Nullable Bundle options);


 /**
     * Same as {@link #startActivity(Intent, Bundle)} with no options
     * specified.
     *
     * @param intent The description of the activity to start.
     *
     * @throws ActivityNotFoundException &nbsp;
     *`
     * @see #startActivity(Intent, Bundle)
     * @see PackageManager#resolveActivity
     */
    public abstract void startActivity(@RequiresPermission Intent intent);

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

/**
 * Common implementation of Context API, which provides the base
 * context object for Activity and other application components.
*(Context API的通用实现,它为Activity和其他应用程序组件提供基本上下文对象。)
 * @hide
 */
public 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);
    }
    ... ...

}

Activity从类层次结构上来说本质上是一个Context,如果大家留意过代码会发现,Activity并非直接继承自Context,而是继承于ContextThemeWrapper。

public class Activity extends ContextThemeWrapper
        implements LayoutInflater.Factory2,
        Window.Callback, KeyEvent.Callback,
        OnCreateContextMenuListener, ComponentCallbacks2,
        Window.OnWindowDismissedCallback, WindowControllerCallback,
        AutofillManager.AutofillClient {

}

而这个ContextThemeWrapper又继承于ContextWrapper。

/**
 * A context wrapper that allows you to modify or replace the theme of the
 * wrapped context.
 */
public class ContextThemeWrapper extends ContextWrapper {

}

/**
 * Proxying implementation of Context that simply delegates all of its calls to
 * another Context.  Can be subclassed to modify behavior without changing
 * the original Context.
 */
public class ContextWrapper extends Context {
  Context mBase;

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

最终的这个ContextWrapper才继承于Context,ContextWrappper就是我们要找的装饰者,在ContextWrapper中有一个Context的引用。

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

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

 

这里可以看到ContextWrapper中的startActivity方法也仅仅是简单地调用了具体组件实现类ContextImpl中对应的方法而已,实质上ContextWrapper中所有方法都仅仅是调用了ContextImpl中对应的方法而已。

 

装饰模式的套路都是很相似的,对于具体的方法的包装扩展则由ContextWrapper的具体子类完成,比如我们的Activity、Service和Application。

 参考《Android源码设计模式》

 

猜你喜欢

转载自blog.csdn.net/zhangying1994/article/details/85521937