策略模式
大家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();
写的不好,希望大家指正。
给个参考链接,更好的理解策略模式