使用null检查的更好方法是,输入类型值?

时间:2013-08-03 02:11:10

标签: java android view

我正在编写一个类似于AQuery的库,但是有一个用于操作元素的精炼语法。

AQuery基本上做的是安全地访问视图层次结构,并允许您在ImageView和TextView等对象上调用子类方法。

我通过使用以下代码编写了一种使用View子类的通用方法:

我的Query对象是用于操纵视图层次结构的基础对象。基本格式如下:

public class Query {
    private View mView;
    // ...
}

接下来是通用接口。这是Query对象的内部接口:

private interface Operation<T extends View> {
    public void execute(T view);
}

接下来是run中的Query方法。这将检查此查询所代表的当前节点,如果成功,则调用Operation对象上的execute方法:

private <T extends View> Query run(Class<T> cls, Operation<T> operation) {
    T t = cls.cast(mView);

    if (t == null) {
        Log.e(TAG, "view is not a " + cls.getSimpleName());
    } else {
        operation.execute(t);
    }

    return this;
}

现在编写模板代码,我使用与此类似的方法来实现功能:

public Query text(final CharSequence str) {
    return run(TextView.class, new Operation<TextView>() {

        @Override
        public void execute(TextView view) {
            view.setText(str);
        }
    });
}

对于修改View层次结构的每个方法,我都必须编写这个类似样板的代码。

有什么方法可以重构这段代码,使text这样的方法更简单?

1 个答案:

答案 0 :(得分:2)

仅供参考,您在这里所拥有的并不是真正检查mView的类型。如果mView不能分配给类型T,则Class.cast将抛出ClassCastException,因此那里的日志消息实际上并不代表发生的情况。当且仅当mView为null时,t == null才为真。

如果没有查询将会执行什么操作,就很难说出你要实现的目标。如果您的使用允许Query的参数化,那么您可以将操作作为其功能。这将为您提供与查询类型匹配的视图的编译时检查。 e.g。

public interface Query<ViewT extends View> {
    void run(ViewT view);
}

public Query<TextView> text(final CharSequence str) {
    return new Query<TextView>() {
        public void run(TextView view) {
            view.setText(str);
        }
    };
}

如果那是不可能的(即在编译时从未知道视图类型),那么您仍然可以参数化它的实现,并且当且仅当参数类型与查询类型匹配时才执行操作。 e.g:

public interface Query {
    void run(View view);
}

private abstract class TypedQuery<ViewT extends View> implements Query {
    private final Class<ViewT> viewType;

    private TypedQuery(Class<ViewT> viewType) {
        this.viewType = viewType;
    }

    public final void run(View view) {
        if (viewType.isInstance(view)) {
            runInternal((ViewT) view);
        } else {
            Log.e(TAG, "view " + view + " is not a " + viewType.getSimpleName());
        }
    }

    protected abstract void runInternal(ViewT view);
}

public Query text(final CharSequence str) {
    return new TypedQuery<TextView>(TextView.class) {
        @Override
        protected void runInternal(TextView view) {
            view.setText(str);
        }
    };
}