Jan 3, 2011

使用Command模式定义BMI的菜单

在学习Android菜单创建之后,给自己前两天做的BMI计算程序添加了一个菜单。正好前两天看了《重构与模式》这本书的用Command模式替换条件调度程序。发现菜单响应正好可以用上。

条件逻辑用来调度请求和执行操作。
为每个动作创建一个Command。把这些Command存储在一个集合中,并用获取及执行Command的代码替换条件逻辑。
                                               ----《重构与设计模式》

1. 创建一个Handler的超类,以后所有菜单的响应都通过继承这个类来实现。

import android.app.Activity;

/**
 * @author Nordy
 *
 */
public abstract class Handler
{

    /**
    * 处理菜单所在的Activity
    **/
    protected Activity activity;

    public Handlers(Activity activity)
    {
        this.activity = activity;
    }

    /**
     * 处理菜单事件
     *
     * @return <code>Boolean</code> <br>
     *         Return <code>false</code> to allow normal menu processing to
     *         proceed, <code>true</code> to consume it here.
     * @see {@link android.app.Activity#onContextItemSelected(android.view.MenuItem)}
     * @see {@link android.app.Activity#onOptionsItemSelected(android.view.MenuItem)}
     */
    public abstract Boolean execute();
}

说明:因为菜单的响应有可能会打开新的Intent,所以在所有的Handler里面都要保存菜单所在的Activity,以便打开新的Activity。以后可能会更根据需要在添加其他的信息。

2. 创建一个菜单响应处理类,继承Handler并实现execute方法。例如,

import android.app.Activity;
import android.app.AlertDialog;
import android.content.DialogInterface;

import com.nordy.BMI.R;

/**
 * 显示程序关于信息
 *
 * @author Nordy
 *
 */
public class AboutHandler extends Handler
{

    public AboutHandler(Activity activity)
    {
        super(activity);
    }

    @Override
    public Boolean execute()
    {
        new AlertDialog.Builder(activity)
                .setTitle(R.string.bmi_about_title)
                .setMessage(R.string.bmi_about_content)
                .setPositiveButton(R.string.confirm,
                                   new AlertDialog.OnClickListener()
                                   {

                                       @Override
                                       public void onClick(DialogInterface paramDialogInterface,
                                                           int paramInt)
                                       {
                                       }

                                   }).show();
        return true;
    }

}


3. 在Activity中创建一个Map存放菜单处理逻辑,添加相应的获取方法:

    ...
    private HashMap<Integer, Handler> handlers;
    ...


    /**
     * register Handlers of menuItem
     */
    public void createMenuHandlers()
    {
        this.handlers = new HashMap<Integer, Handlers>();
        this.handlers.put(R.id.menu_about, new AboutHandler(this));
    }



    /**
     * Find Menu Handler
     *
     * @param item
     *            MenuItem
     * @return Handler of given MenuItem
     */
    private Handlers lookupHandlerBy(MenuItem item)
    {
        return this.handlers.get(item.getItemId());
    }

4. 然后在菜单创建和响应中:

    @Override
    public boolean onCreateOptionsMenu(Menu menu)
    {

        this.getMenuInflater().inflate(R.menu.menu, menu);
        this.createMenuHandlers();

        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item)
    {
       
        this.lookupHandlerBy(item).execute();

        return true;
    }

至此,大功告成。

附:不用Command模式,onOptionsItemSelected方法可能会是这样子:
@Override
public boolean onOptionsItemSelected(MenuItem item)
{

    switch (item.getItemId())
    {
        case R.id.menu_about:
            //处理逻辑 
            return true;
        // 其他菜单项处理逻辑 ... 
        default:
            return super.onOptionsItemSelected(item);
    }
}

这样子菜单项多了之后,会造成代码膨胀。而且相同的菜单处理在其他Activity中无法重用,影响灵活性。使用Command模式之后,以后在扩展菜单处理时只要再创建一个Handler并注册到相应的Activity上即可。

No comments:

Post a Comment