应用较广泛模式之装饰者模式

一年逛一次设计模式,每次都有新感觉!

Posted by 夏敏的博客 on October 9, 2017

设计模式系列仍旧没结束,让我们继续吧..

装饰者模式是我个人比较喜欢的一个设计模式,为什么这么说呢,使用装饰者模式给我们的程序提供了一种动态扩展的功能,我们可以在不动原有的类的情况下添加新功能,这样,我们甚至能一层套一层最后装饰了好多层,增加了很多功能,而这些功能却能够灵活扩展.

定义

装饰者模式动态地给一个对象添加一些额外的职责。注意:动态的给一个对象,而不是对整个类添加额外职责,说明此模式将采用的结构是组合而不是继承;要给一个对象添加职责,通常可以使用其类的派生类对象替换当前对象,但这显得不够灵活.我们的装饰模式能够更加灵活

应用场景

我们在Android中的主要应用有: 给滚动列表动态添加头部试图啊, 给Adapter动态添加指定动画啊, 拦截一些接口数据等.
在我们代码中,常见的Wrapper,Decorator类基本上都是装饰模式的应用.

应用思路

我们以一个人的赚钱功能来举例,我们定义一个赚钱性质的接口,其提供获取金额和增加金额两个方法

接口

interface Money {
	int getMoney();
	void addMoney(int num);
}

我们生成一个实现类,这个是初始化状态,每个人有100块钱,

class PersonImp implements Money {

	int money = 100;

	public int getMoney() {
		return money;
	}

	public void addMoney(int num) {
		money += num;
	}
}

再写一个基础装饰类

abstract class PersonWrapper implements Money {
	Money person;

	public PersonWrapper(Money money) {
		person = money;
	}
}

好了,假设现在我们需要让一个Person收益翻倍,代码如下.

class DoublePersonWrapper extends PersonWrapper {

	public DoublePersonWrapper(Money money) {
		super(money);
	}

	public int getMoney() {
		return person.getMoney();
	}

	public void addMoney(int num) {
		person.addMoney(num * 2);
	}
}

那么在应用时:

    public static void main(String[] args) {
		// 初始化一个有100块钱的小明对象
		Money xiaoming = new PersonImp();
		xiaoming.addMoney(10);
		System.out.println("xiaoming: " + xiaoming.getMoney());
		// 小明拥有收益翻倍功能
		xiaoming = new DoublePersonWrapper(xiaoming);
		xiaoming.addMoney(10);
		System.out.println("xiaoming: " + xiaoming.getMoney());
	}
	
	
xiaoming: 110
xiaoming: 130

实际应用场景

  1. Context是Android中对装饰模式的经典应用,具体见另一篇博文深入Context

  2. 对Adapter进行扩展,对RecyclerView进行扩展,见KeepGank加载更多组件

  3. 对接口进行拦截扩展 以下是我项目中的一个应用,使用该类的时候会传进来一个接口.我需要在不改变调用方以及接收方逻辑的情况下拦截数据做一些UI逻辑处理,即可这么写.记得一年前我是通过父类提供通知方法通知子类的形式实现的,实在是太挫了. ``` java private class TtsListenerWrapper implements TtsListener { private TtsListener mTtsListener;

     public TtsListenerWrapper(TtsListener ttsListener) {
         mTtsListener = ttsListener;
     }
    
     @Override
     public void onBegin(int requestId) {
         mTtsListener.onBegin(requestId);
         String text = mTtsMap.get(requestId);
         if (!TextUtils.isEmpty(text)) {
             showSubtitile(text);
             mTtsMap.remove(requestId);
         }
     }
    
     @Override
     public void onError(int requestId) {
         mTtsListener.onError(requestId);
         removeTextWindow();
     }
    
     @Override
     public void onEnd(int requestId) {
         mTtsListener.onEnd(requestId);
         removeTextWindow();
     }  }
    

```

作者:Anderson大码渣,欢迎关注我的简书: Anderson大码渣