Android源码之策略模式

策略模式

大家Android编程中用的最多的类估计View算其中之一,View中有一个OnClickListener变量叫做mOnClickListener,其实它这里就用到了策略模式。首先我们知道View相应点击事件有两种方式:

一.获取到View对象的时候,给它设置OnClickListener对象

        View view = new View(this);
        view.setOnClickListener(new View.OnClickListener()
        {
            
            @Override
            public void onClick(View v)
            {
                // TODO Auto-generated method stub
                
            }
        });
二.View类定义的时候实现OnClickListener接口,并且复写onClick方法,用户点击的时候由系统回调该方法,显然Google并没有这么做

    public class View implements OnClickListener
    {
        public View()
        {
            setOnClickListener(this);
        }
        public void onClick(View v)
        {
            
        }
    }


灵活性:

为什么Google没有用第二种方法去实现,设计模式中有两个原则是这么说的。

1.少用继承,多用组合 (因为用继承在编译的时候就已经敲死了,无法在运行时动态设置,而组合可以认为是变量,可以在运行的时候动态修改,比如上面mOnClickListener)

2.有一个比是一个好(有一个:可以认为类中有一个这种变量,是一个:也就是继承,继承这个变量所属的类,继承了View那么它就是个View,编译就已经确定,其实这是上面这个原则的另一种说法)


回到上面第一种实现方式:OnClickListener,是运行的时候在代码中动态设置的,而且在以后情况变化之后可以重新设置另外一个OnClickListener,也就是设置另外一种行为

回到上面第二种实现方式:继承了就是写死了,写死了就无法在程序中动态的给View设置OnClickListener行为了。


对比一下哪种方式的灵活性更好,当然是前者。


资源利用率:

所有控件(TextView、Button、或者我们自定义的控件)都是继承自View的,如果子类要响应点击事件,那按照上述两种实现方法,分别实现如下,以Button为例

1.代码中动态设置

        Button mButton = new Button(this);
        mButton.setOnClickListener(new View.OnClickListener()
        {
            
            @Override
            public void onClick(View v)
            {
                // TODO Auto-generated method stub
                
            }
        });

2.继承View复写onClick方法,当然如果不复写onClick方法,相应系统点击回调是调用的父类View的onClick方法

    public class View implements OnClickListener
    {
        public View()
        {
            setOnClickListener(this);
        }
        public void onClick(View v)
        {
            
        }
      

public class Button extends View
{
    public void onClick(View v)
    {
        // TODO Auto-generated method stub
    }
}

这两种方式都能实现响应用户点击,第一个动态设置的,一个是静态继承写死的,当然在响应用户点击这件事情上,他们达到的效果是一样的,就算第二种方式不去复写onClick方法,也是能够响应到父类onClick中.


我现在想写一个自定义View只是用来展示,无需响应用户点击。

按照第一种方式的实现:继承View并且不设置OnClickListener即可

按照第二种方式的实现:继承View复写onClick方法,这个方法不识实现任何内容。


区别在于第二种方式多了一个无用的onClick方法,其实根本就不会用到,第二种方式会造成凡是继承View的类都会有onClick这个方法,但是有些子类并不需要这个方法,真是浪费,而第一种方式不设置OnClickListener就不会多出来多余的方法,设置了才会有。


所以对于onClick这个方法是可以有也可以无的、第一种方法能够做到可实现,可不实现,第二种方法就是强制你必须定义这个方法。所以在某些不需要响应点击的控件上,这个onClick方法就浪费掉了。

对于onClick方法它并不是固定的,而是可变的,对于这种可变的部分我们要单独抽离出来一个接口,在需要的时候去实现,而不是继承它的接口强制实现。


所以资源利用率:明显后者低。


策略模式的定义:定义了算法族,并分别封装起来,让它们之间可以相互替换。此模式让算法的变化独立于使用算法的客户。

算法族:(onClick的不同的实现方式,可以认为是onClick的算法族)

分别封装起来:这里没有体现出来,因为我直接用的new OnClickListener,可以理解为同一个接口分别不同的实现,如下面ButtonOnClickListener、TextViewOnClickListener

public class TextViewOnClickListener implements OnClickListener
{
    
    public void onClick(View v)
    {
        System.out.println("========>>>>>>>>>>>ButtonOnClickListener");
    }
    
}
public class ButtonOnClickListener implements OnClickListener
{
    
    public void onClick(View v)
    {
        System.out.println("========>>>>>>>>>>>ButtonOnClickListener");
    }
    
}
让它们之间可以相互替换:如Button可以设置ButtonOnClickListener也可以设置TextViewOnClickListener,TextView可以设置TextViewOnClickListener也可以设置ButtonOnClickListener

此模式让算法的变化独立于使用算法的客户:这个OnClickListener由调用者去设置,既不是继承里面写死了,也不是帮你写好了,而是由调用根据需求去实现不同的onClickListener。


由策略模式引发出来的三大OO设计原则:

1.封装变化部分

2.多用组合,少用继承

3.针对接口编程,不针对实现编程


关于第三个原则:

如上面例题,我们都是用的OnClickListener这个接口对象,并非它的实现类,无需考虑子类实现。

即便我们封装了一个ButtonOnClickListener,我们也最好按如下方式写

 OnClickListener onClickListener = new ButtonOnClickListener();


写的不好,希望大家指正。


给个参考链接,更好的理解策略模式

点击打开链接

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值