从简单的说起:
一、在只有值传递的语言中,通过Wapper把实参Wapper之后,实现副作用:
在工具箱里写上我们要用的Wrapper:
- public class Wrapper<T extends Object> {
- public T object;
- public Wrapper() {
- object = null;
- };
- public Wrapper(T object) {
- this.object = object;
- }
- }
下面我们看看一个从内部类获得副作用的例子:
由于内部类使用外部变量必须是final的,这样试图使用一个变量直接得到
内部类操作的结果不能够实现,这时候我们的Wrapper派上了用场:
- final Wrapper<String> wrapper = new Wrapper<String>();
- Display.getDefault().syncExec(new Runnable() {
- public void run() {
- wrapper.object = ....;
- }
- }
我们可以成功的从一个内部类中获得我们需要的数据。
下面我们看一个经典的swap函数:
- void swap(int a,int b){
- int temp = a;
- a = b;
- b = temp;
- }
这个简单的swap函数不起作用的,而java等语言参数传递只支持值传递,
所以不管是参数是基本类型还是Object类型,都不能写出可以swap两个值的函数。
如果我们非得想有这么一个swap函数来交换两个值,那该怎么办?这时候wapper又派上用场了。
在我们的工具箱找到Wrapper:
写我们的交换函数:
- void swap(Object a,Object b){
- Object temp = a.value;
- a.value = b.value;
- b.value = temp;
- }
- String a = "abc";
- String b = "bcd";
- Wrapper<String> wrapperA = new Wrapper<String>(a);
- Wrapper<String> wrapperB = new Wrapper<String>(b);
- swap(wrapperA,wrapperB);
在用javascript写XPCOM的时候,数组及其大小作为返回值(由于idl与实现语言无关,
需要返回数组的大小),两个返回值,javascript是不支持的,并且在javascript
只有值传递的语言,使用参数直接作为返回值是不能实现的,这时候Wapper就派上了
用场:
- idl:
- void getArray(out unsigned long count,[retval, array, size_is(count)] out string aArray);
js实现:
- getArray: function(aCount){
- aCount.value = this.aArray.length;
- return this.aArray;
- };
使用方法:
- var aCount = {};一个Wapper
- var array = xx.getArray(aCount);
- xxx.alert(aCount.length);
二、控制实例产生的个数/生命周期:
最常见的一个Wrapper要算单例模式了:
- public class Singleton{
- private static Singleton instance = new Singleton();
- private Singleton(){
- }
- public static Singleton getInstance(){
- return instance;
- }
- }
这个Wrapper或许有点特别,自己Wrapper自己,来控制实例产生的个数/生命周期。
上次写了一个获取Post数据的firefox插件,XPCOM nsPostDataManager最早使用:
- var catman = Cc["@mozilla.org/categorymanager;1"].getService(Ci.nsICategoryManager);
- catman.addCategoryEntry("JavaScript global property",
- CLASS_NAME,
- CONTRACT_ID,
- true,
- true);
来注册。
这样可以在网页全局访问getPostData和clearRequests接口方法。但是结果去每次都为空,跟踪发现
每打开一个新的Tab页,nsPostDataManager就会有一个新的实例生成,从而使得收集post请求的实例,
和在页面要使用的实例不是一个。这时候Wrapper又可以出头露面了,再写一个Wrapper组件nsPostDataService::
- getPostData: function(aCount){
- //在XPCOM中getService每次使用一个实例,而createInstance每次创建一个实例
- var nsPostDataManager = Cc["@ibm.com/nspostdatamanager;1"].getService(Ci.nsIPostDataManager);
- return nsPostDataManager.getPostData(aCount);
- },
- clearRequests: function(){
- var nsPostDataManager = Cc["@ibm.com/nspostdatamanager;1"].getService(Ci.nsIPostDataManager);
- return nsPostDataManager.clearRequests();
- }
这时候把nsPostDataService注册成网页全局访问的就可以了。
三、控制对象的访问:
Proxy模式其实也是一个Wrapper,通过Wrapper这个对象来控制对象的访问,并转发消息到实际对象。
四、为对象动态增加行为:
Proxy模式的动态代理可以实现AOP,为对象动态增加行为。Spring的AOP就是使用了Java动态代理。
装饰模式可以动态的Wrapper对象,来为对象增加行为:
BufferedInputStream bis = new BufferedInputStream(new FileInputStream(file));
Extension Object模式则可以为Object动态添加新的行为而不改变已有的接口,然后Query到需要的接口,使用新行为。
Wrapper还有很多使用的场合,希望大家补充。