美文网首页
Android与设计模式(3)代理/适配器/装饰/享元

Android与设计模式(3)代理/适配器/装饰/享元

作者: 浪里_个郎 | 来源:发表于2020-03-24 00:28 被阅读0次

    详细代码请见https://github.com/zackLangChina/DesignPatternLearning

    Android与设计模式(1)
    单例模式 ** 工厂模式 ** 策略模式 ** 命令模式
    Android与设计模式(2)
    观察者模式 ** 备忘录模式 ** 模板方法模式 ** 中介者模式
    Android与设计模式(3)
    代理模式 ** 适配器模式 ** 装饰模式 ** 享元模式
    Android与设计模式(4)
    外观模式 ** 桥接模式 ** MVP模式

    9,代理模式

    代理模式

    使用场景:

    是为某个对象提供一个代理对象,并且由代理对象控制对原对象的访问。意义在于:客户端与服务端解耦,以及在代理中封装一些功能(比如AIDL中代理类Proxy封装了binder通信的功能)。
    代理模式分为静态代理和动态代理。区别为静态代理使用时需要通过new出代理类,而动态代理是使用APT、反射等方式创建代理类。
    很多框架(如retrofit)中通常会使用java.lang.reflect包中的Proxy和InvocationHandler来实现动态代理。当我们使用proxy的方法:

    Object newProxyInstance(ClassLoader var0, Class<?>[] var1, InvocationHandler var2)
    

    内部实现会通过反射获得的具备var1接口的实例,并且这个实例是被装饰过的,每当调用var1中方法时,都会首先调用InvocationHandler 接口实现类var2中的方法:

    Object invoke(Object var1, Method var2, Object[] var3)
    

    这种插入代码逻辑的编程思想,就叫做AOP,面向切片编程。
    代理模式有些类似中介模式,区别如下:
    中介模式中,双方都可以互相访问;代理模式中,访问是单向的,只能由客户端通过代理访问服务端。

    Android中的应用:

    AIDL。代码示例部分会模仿AIDL的实现(没有binder)

    组成部分

    客户端 | 代理 | 服务端

    代码示例:

    import java.util.HashMap;
    import java.util.Map;
    //模仿android中的ServiceManager,管理所有service(其实管理的是代理proxy)
    class ProxyServiceManager {
        private static ProxyServiceManager mInstant = new ProxyServiceManager();
        private Map<String, IProxyService> mProxyList = new HashMap<String, IProxyService>();
    
        private ProxyServiceManager() {
        }
    
        public static ProxyServiceManager getInstance() {
            return mInstant;
        }
    
        public void addService(String name,IProxyService service) {
            mProxyList.put(name,service);
        }
    
        public IProxyService getService(String name) {
            return mProxyList.get(name);
        }
    }
    //服务和代理的公用接口。不同服务实现不同的接口。类似于AIDL
    interface IProxyService {
        void doSomething();
    }
    //类似于AIDL生成的代码的结构(没有binder),真正的服务中嵌套一个内部proxy类
    class ProxyService implements IProxyService {
        public String SERVICE_NAME_PROXYSERVICE = "proxy";
        private ProxyService mInstant;
    
        public ProxyService() {
            mInstant = this;
            ProxyServiceManager.getInstance().addService(SERVICE_NAME_PROXYSERVICE,new MyProxy());
        }
        //服务端的接口实现,业务代码放在这
        @Override
        public void doSomething() {
            System.out.println("now, Service do something");
        }
        //内部proxy类,实际上注册到ProxyServiceManager的是它。负责与真正的service通信
        class MyProxy implements IProxyService {
            //proxy的接口实现,只负责通信
            @Override
            public void doSomething() {
                System.out.println("proxy call Service do something...");
                mInstant.doSomething();
            }
        }
    }
    

    10,适配器模式

    适配器模式

    使用场景:

    将一个类的接口变换成客户端所期待的另一种接口,从而使原本因接口不匹配而无法在一起工作的两个类能够在一起工作。
    说人话!
    可以把Adapter想象成一个加工车间,把原材料送进去,产出的是成品。客户端只要伸手拿成品就行,不需要关心加工过程。

    Android中的应用:

    ListView或RecycleView通过适配器来获取子View。
    只要把子View的布局和所有子VIew中资源ID对应的数据给到Adapter,就能转成客户端所需的View。
    代码示例部分会模仿这块实现。

    组成部分

    客户端 | 适配器

    代码示例:

    import java.util.ArrayList;
    import java.util.List;
    //目标产品
    class Cake {
        private int sugers;
        private int eggs;
    
        public Cake(int sugers, int eggs) {
            this.sugers = sugers;
            this.sugers = eggs;
            System.out.println("I am Cake, made by " +  sugers + " sugers and " + eggs + " eggs");
        }
    }
    //适配器接口,我们可以有不同的适配器实现
    interface ICakeAdapter {
        List<Cake> productCake();
    }
    //适配器实现,用糖和鸡蛋做蛋糕
    class CakeAdapter implements ICakeAdapter{
        private int[] sugerList;
        private int[] eggList;
    
        public CakeAdapter(int[] sugerList, int[] eggList) {
            if(sugerList.length!=eggList.length) {
                System.out.println("原料数量不匹配");
                return;
            }
            this.sugerList = sugerList;
            this.eggList = eggList;
        }
        //用糖和鸡蛋批量制作蛋糕提供给客户端
        @Override
        public List<Cake> productCake() {
            List<Cake> cakes = new ArrayList<Cake>();
            for(int i=0;i<sugerList.length;i++) {
                cakes.add(new Cake(sugerList[i],eggList[i]));
            }
            sugerList = null;
            eggList = null;
            return cakes;
        }
    }
    
    

    11,装饰模式

    代理模式

    使用场景:

    装饰模式在功能上类似于通过子类继承,扩展父类的功能。但是装饰模式相对于继承,有以下好处:
    1,可以动态地切换需要装饰的对象,比生成子类更灵活。
    2,因为装饰类可以切换装饰对象,所以一个装饰类可以用来给一批父类相同的子类来搞装饰,而不用像继承那样,扩展一个类就得定义一个子类

    Android中的应用:

    Context

    ContextWrapper(ContextThemeWrapper的父类(Acrtivity的父类))是一个地地道道的装饰者。它本身并没有实现业务功能,只是调用了ContextImpl的方法,所以ContextWrapper是ContextImpl的装饰类。
    同样的,Activity、Service和Application作为ContextWrapper的子类,一样是ContextImpl的装饰类!因为他们仅仅是对Context接口的实现进行了装饰。
    这里其实并没有很体现装饰模式的修饰,但如果未来Context有更多的实现类...嗯,那就牛逼了。

    组成部分

    接口或基类 | 功能实现类或子类 | 装饰类

    代码示例:

    interface Sword {
        void showProperty();
    }
    //一把黄金剑
    class GoldSword implements Sword {
    
        @Override
        public void showProperty() {
            System.out.println(getClass().getName());
        }
    }
    //一把木剑
    class WoodSword implements Sword {
    
        @Override
        public void showProperty() {
            System.out.println(getClass().getName());
        }
    }
    //装饰类
    class SwordDecorator implements Sword {
        Sword mBase;
    
        public SwordDecorator(Sword mBase) {
            this.mBase = mBase;
        }
        //可以动态更换需要装饰的类
        public void attachBase(Sword mBase) {
            this.mBase = mBase;
        }
        //给大宝剑们上Buff!
        @Override
        public void showProperty() {
            mBase.showProperty();
            System.out.println("+8 稀有品质!");
        }
    }
    

    12,享元模式

    享元模式

    使用场景:

    享元模式通过共享技术实现相同或相似对象(享元)的重用,避免大量重复申请内存导致的问题。
    享元工厂负责生产和管理享元,当客户端申请享元的时候,首先查询是否有现成的享元,如果没有,再生产一个新的享元。

    Android中的应用:

    线程池

    组成部分

    享元接口 | 具体的享元类 | 享元工厂

    代码示例:

    import java.util.ArrayList;
    import java.util.List;
    
    //享元工厂
    class Library {
        //可借的书,书池,借书时如果书池中有要借的书,就不用生产新书了
        private List<Book> bookList = new ArrayList<Book>();
        //借书出去
        public Book borrowBook(Class clazz) {
            for(Book book : bookList) {
                if(clazz.isInstance(book)) {
                    bookList.remove(book);
                    book.borrow();
                    return book;
                }
            }
            //没有找到要借的书,生产一本
            try {
                Book book = (Book) clazz.newInstance();
                book.borrow();
                return book;
            } catch (InstantiationException e) {
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            }
            return null;
        }
        //还书回来
        public void returnBook(Book returnBook) {
            //放入书架
            bookList.add(returnBook);
            returnBook.returnBook();
        }
    }
    //享元接口(书),可以借书和还书
    interface Book {
        void borrow();
        void returnBook();
    }
    //数学书
    class MathBook implements Book {
        public MathBook() {
            System.out.println("create " + getClass().getName());
        }
    
        @Override
        public void borrow() {
            System.out.println("borrow " + getClass().getName());
        }
    
        @Override
        public void returnBook() {
            System.out.println("return " + getClass().getName());
        }
    }
    //漫画书
    class ComicBook implements Book {
        public ComicBook() {
            System.out.println("create " + getClass().getName());
        }
    
        @Override
        public void borrow() {
            System.out.println("borrow " + getClass().getName());
        }
    
        @Override
        public void returnBook() {
            System.out.println("return " + getClass().getName());
        }
    }
    

    相关文章

      网友评论

          本文标题:Android与设计模式(3)代理/适配器/装饰/享元

          本文链接:https://www.haomeiwen.com/subject/geqnyhtx.html