欢迎点击“AntDream”关注
在日常开发过程中时常需要用到设计模式,但是设计模式有23种,如何将这些设计模式了然于胸并且能在实际开发过程中应用得得心应手呢?和我一起跟着《Android源码设计模式解析与实战》一书边学边应用吧!
今天我们要讲的是装饰模式(包装模式)
定义
动态的给一个对象添加一些额外的职责。就增加功能来说,装饰模式比生成子类更为灵活
使用场景
- 需要透明且动态地扩展类的功能时
使用例子
- Android源码中的ContextWrapper
实现
四大角色
- 抽象组件:可以是抽象类或接口,是被装饰类的原始对象
- 组件具体实现类:该类是抽象组件的具体实现,也是我们装饰的具体对象
- 抽象装饰者:为了装饰我们的组件对象,其内部一定要有一个指向组件对象的引用。在大多数情况下,该类为抽象类,需要根据不同的装饰逻辑实现不同的子类。如果装饰逻辑单一,只有一个的情况下我们可以省略该类直接作为具体的装饰者
- 具体的装饰者:对抽象装饰做具体的实现
实现的要点
- 要有具体的被装饰对象
- 根据需要创建抽象装饰者
- 不论是抽象装饰者还是具体的装饰者,都会持有被装饰组件的引用
- 具体的装饰者中肯定需要有被装饰组件的方法,并根据需要加以扩展
实现方式
首先先熟悉下装饰模式的概念
代码语言:javascript复制public class DecoratorActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initData();
initView();
}
private void initData() {
//初始化数据
}
private void initView() {
//初始化页面
}
}
- 上面的代码我们应该比较熟悉,这就比较类似装饰模式中装饰者的职责,就是动态地扩展了类的功能
下面我们以对在代理模式一文中的示例代码进行改造来简单应用装饰模式
首先抽象主题类Notify类不变
代码语言:javascript复制public abstract class Notify {
protected Context context;
protected NotificationManager notificationManager;
protected NotificationCompat.Builder builder;
public Notify(Context context) {
this.context = context;
notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
builder = new NotificationCompat.Builder(context);
builder.setSmallIcon(R.drawable.ic_launcher)
.setContentIntent(PendingIntent.getActivity(context, 0,
new Intent(context, NotifyActivity.class),
PendingIntent.FLAG_UPDATE_CURRENT));
}
/**
* 发送一条通知
*/
public abstract void send();
/**
* 取消一条通知
*/
public abstract void cancel();
}
被代理类(这里是被装饰类)NotifyNormal要稍微变动下
代码语言:javascript复制public class NotifyNormal extends Notify {
public NotifyNormal(Context context) {
super(context);
}
@Override
public void send() {
Notification notification = builder.build();
notificationManager.notify(0, notification);
}
@Override
public void cancel() {
notificationManager.cancel(0);
}
}
接下来是抽象装饰者
代码语言:javascript复制public abstract class NotifyDecorator extends Notify {
private Notify notify;
public NotifyDecorator (Context context, Notify mNotify) {
super(context);
this.notify = mNotify;
}
@Override
public void send() {
notify.send();
}
@Override
public void cancel() {
notify.cancel();
}
}
- 这里NotifyDecorator持有了被装饰组件Notify的引用,并且包含Notify的send方法和cancel方法
具体的装饰者,原来分别有NotifyNormal、NotifyBig、NotifyHeadersUp,这里对应三个具体的装饰者
- NotifyNormalDecorator
public class NotifyNormalDecorator extends NotifyDecorator {
public NotifyNormalDecorator (Context context, Notify notify) {
super(context, notify);
}
@Override
public void send() {
builder.setContent(new RemoteViews(context.getPackageName(), R.layout.layout_notify_normal));
super.send();
}
}
- NotifyBigDecorator
public class NotifyBigDecorator extends NotifyDecorator {
public NotifyBigDecorator(Context context, Notify notify) {
super(context, notify);
}
@Override
public void send() {
builder.setContent(new RemoteViews(context.getPackageName(), R.layout.layout_notify_normal));
builder.setCustomBigContentView(new RemoteViews(context.getPackageName(), R.layout.layout_notify_normal));
super.send();
}
}
- NotifyHeadsUpDecorator
public class NotifyHeadsUpDecorator extends NotifyDecorator {
public NotifyHeadsUpDecorator(Context context, Notify notify) {
super(context, notify);
}
@Override
public void send() {
builder.setContent(new RemoteViews(context.getPackageName(), R.layout.layout_notify_normal));
builder.setCustomBigContentView(new RemoteViews(context.getPackageName(), R.layout.layout_notify_normal));
builder.setCustomHeadsUpContentView(new RemoteViews(context.getPackageName(), R.layout.layout_notify_normal));
super.send();
}
}
以上都是在被装饰对象NotifyNormal的基础上增加或更改了通知的布局
代理类NotifyProxy也要相应的做修改
代码语言:javascript复制public class NotifyProxy extends Notify{
private NotifyDecorator notifyDecorator;
public NotifyProxy (Context context) {
super(context);
Notify notify = new NotifyNormal(context);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
notifyDecorator = new NotifyHeadsUpDecorator(context, notify);
} else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
notifyDecorator = new NotifyBigDecorator(context, notify);
} else {
notifyDecorator = new NotifyNormalDecorator(context, notify);
}
}
@Override
public void send() {
notifyDecorator.send();
}
@Override
public void cancel() {
notifyDecorator.cancel();
}
}
调用的入口依然没变
代码语言:javascript复制new NotifyProxy(MainActivity.this).send();
总结
- 从上面我们对代理模式中的示例代码进行改造的过程我们可以看出,装饰模式主要在于扩展了类的功能。
- 装饰模式通过在被装饰组件的方法执行之前或之后加入新的方法来实现功能的扩展
装饰模式和代理模式的区别
- 装饰模式是对客户端以透明的方式扩展对象的功能,是继承关系的一种替代;而代理模式则是给一个对象提供一个代理对象,并由代理对象来控制对原有对象的引用
- 装饰模式应该为所装饰的对象增加功能,而代理对象对所代理的对象施加控制,但不对对象本身的功能进行增强