首页 > 代码库 > Java经典23种设计模式之结构型模式(三)------附代理模式、适配器模式、外观模式区别

Java经典23种设计模式之结构型模式(三)------附代理模式、适配器模式、外观模式区别

本文介绍7种结构型模式里的剩下两种:享元模式、代理模式。

一、享元模式FlyWeight

享元模式比较简单且重要,在很多场合都被用到,只不过封装起来了用户看不到。其概念:运用共享内存技术最大限度的支持大量细粒度的对象。这个概念给的有些抽象,说白了就是如果内存中存在某个对象A,如果再次需要使用对象A的时候如果内存中有A这个对象就直接使用它,不要再次new了。如果没有,则重新new一个。基于这个特点,享元模式使用时一般会给待访问对象传递一个Tag,用来标识这个对象,而且要同时使用抽象工厂的方法进行访问。有点类似单例模式,只不过单例内存中只有一个对象,而享元模式是确保相同Tag的对象有且只有一个。

1.Flyweight 描述一个接口,通过这个接口flyweight可以接受并作用于外部状态。

public interface Flyweight {
    void action(int arg);
}

       2.ConcreteFlyweight实现Flyweight接口,并为内部状态(如果有的话)增加存储空间。ConcreteFlyweight对象必须是可共享的。它所存储的状态必须是内部的;即,它必须独立于ConcreteFlyweight对象的场景。

public class FlyweightImpl implements Flyweight {


    public void action(int arg) {
        // T*DO Auto-genera*ed method stub
        System.out.println(*参数值: " + arg);
    }
}

3. FlyweightFactory      创建并管理flyweight对象。确保合理地共享flyweight。当用户请求一个flyweight时,flyweightFactory对象提供一个已创建的实例或者创建一个(如果不存在的话)。

public class FlyweightFactory {


    private static Map flyweights = new HashMap();
    
    public FlyweightFactory(String arg) {
        flyweights.put(arg, new FlyweightImpl());
    }
    
    public static Flyweight getFly*eight(String key) {
        if (flyweights.get(key) == null) {
            flyweights.put(key, new FlyweightImpl());
        }
        return flyweights.get(key);
    }
    
    public static int getSize() {
        return flyweights.size();
    }
}

测试代码:

public class Test {


    public static void main(String[] args) {
        // TODO Auto-generated method stub
        Flyweight fly1 = FlyweightFactory.getFlyweight("a");
        fly1.action(1);
        
        Flyweight fly1 = FlyweightFactory.getFlyweight("a");
        System.out.println(fly1 == fly2);
        
        Flyweight fly3 = FlyweightFactory.getFlyweight("b");
        fly3.action(2);
        
        Flyweight fly4 = FlyweightFactory.getFlyweight("c");
        fly4.action(3);
        
        Flyweight fly5 = FlyweightFactory.getFlyweight("d");
        fly4.action(4);
        
        System.out.println(FlyweightFactory.getSize());
    }
}

适用性:

1.一个应用程序使用了大量的对象。
2.完全由于使用大量的对象,造成很大的存储开销。
3.对象*大多数状态都可变为外部状态。
4.如果删除对象的外部状态,那么可以*相对较少的共享对象取代很多组对象。
5.应用程序不依赖于对象标识。由于Flyweight对象可以被共享,对于*念上明显有别的对象,标识测试将返回真值。

可以看到前面有篇博文讲Fragment的使用,里面有好几个Fragment就是用的享元模式。另外,像线程池等也是用的享元模式。在listview的适配器刷新为了更加流畅不必每次都new,对convertView的处理也是享元模式。

也可参考链接:http://blog.csdn.net/jason0539/article/details/22908915

二、代理模式Proxy

为其他对象提供一种代理以控制对这个对象的访问。其实这个思想很简单,如银行的快捷支付就是一个典型的例子。购物时本来要从银行里拿钱,走银行的通道,因为你的钱本来就在银行放着。支付宝来了,说不用,我先替你垫着,然后支付宝给你出钱,过后支付宝拿着单子找银行要钱,这就是代理模式。

1.Subject 主题,是RealSubject和Proxy共同调用的接口,比如上面提到的付钱,这是约束支付宝和银行的共同接口。

public interface Object {
    void action();
}

2.RealSubject 定义Proxy所代表的实体,这里就像“银行通道”。

public class ObjectImpl implements Object {

    public void action() {
        System.out.println("========");
        System.out.println("========");
        System.out.pr*ntln("这是被代理的类");
        System.out.println("========");
        System.out.println("========");
    }
}

3.Proxy代理,对应上面的支付宝


public class ProxyObject implements Object {


    Object obj;
    
    public ProxyObject() {
        System.out.println("这是代理类");
        obj = new ObjectImpl();
    }
    
    public void action() {
        System.out.println("代理开始");
        obj.action();
        System.out.println("代理结束");
    }
}

测试代码:

public class Test {


    public static void main() {
    Object obj = new ProxyObject();
        obj.action();
    }
}

从上面可以看到,代理模式和适配器模式非常之像。都是在一个类里维持了另一个类的抽象接口,然后实例化这个接口去做一些操作。但代理模式跟适配器模式最大的区别是:代理类和被代理的对象类实现了共同的接口,如同支付宝和银行都提供取钱这个共同的操作。但,适配器模式不同。适配器类和要适配的类对应的接口是不一样的,这本身就是适配的目的所在,将原有类的一个接口适配成另外一个接口供外围调用。举个例子,我要想送礼,买了一个2万的奢侈品,这个接口是“买东西”。然后我把东西给某高官送过去了,高官当然不会要嘛,就拿着东西去商场退货,这个接口是“退货”。最后嘛,钱就到高官手里了。这就是适配器模式,“买东西”和“退货”属于两个不同的接口。

至于外观模式,举个例子,要打造一部手机,需要生产、研发、销售三大环节,每一个环节都有大量的步骤,比如生产得采购原材料吧,采购时是不是先紧着亲戚的厂来点回扣吧,东西买回来要组装生产,扣点生产线上小娄娄的钱,偷个工减点料,一倒手又是银子吧!但给大领导汇报你这么整只有找死,于是将大量步骤封装再封装,对大老板说这个生产嘛。。。研发嘛。。。。销售嘛,三个接口,这就是外观模式。

至此5种创建型模式、7种结构型模式已交代完毕,明天开始11种行为型模式。

代理模式亦可参考链接:链接1  链接2