使用多个供应商时如何避免if / else?

时间:2013-08-12 18:44:54

标签: java design-patterns if-statement

当从多个位置查询数据并且应该在第一个非空实例上返回时,有没有办法避免使用if / else语句?

我正在尝试从3个不同的位置(用户首选项,组首选项和系统首选项)为用户加载首选项。例如:

Preference getPreference(User user, Preference.Type type) {

    Preference preference = getUserPreferenceFor(user, type);
    if (preference != null) {
        return preference;
    }

    preference = getGroupPreferenceFor(user, type);
    if (preference != null) {
        return preference;
    }

    return getSystemPreferenceFor(user, type);
}     

我想避免使用这些,如果检查并将这些方法链接在一起,以便行为保持相同,但代码不会有这种丑陋的重复。

我已经想到了一些解决方案,但是没有这些解决方案是优雅的。例如,一种方法是让每个方法都提供默认值,但这只会分散if语句。

Preference getPreference(User user, Preference.Type type) {
    Preference preference = getUserPreferenceFor(user, type);
    if (preference != null) {
        return preference;
    }

    return getGroupPreferenceFor(user, type);
}

Preference preference getGroupPreferenceFor( 
    if (preference != null) {
        return preference;
    }

    return getSystemPreferenceFor(user, type);
} 

另一种方法是使用一些提供者接口,为每个提供者创建子类并迭代提供者,直到找到第一个非null。

public interface PreferenceProvider {
    Preference getPreference(User user, Preference.Type type);
}

public class UserPreferenceProvider implements PreferenceProvider {
    public Preference getPreference(User user, Preference.Type type) {
        ...
    }
}
... group and system provider the same way

final static PreferenceProvider[] providers = new PreferenceProvider[] {
    new UserPreferenceProvider(),
    new GroupPreferenceProvider(),
    new SystemPreferenceProvider()
};

Preference getPreference(User user, Preference.Type type) {
    Preference preference = null;
    for (PreferenceProvider provider : providers) {
        preference = provider.getUserPreferenceFor(user, type);
        if (preference != null) {
            return preference;
        }
    }
}

最后一个足够接近但它仍然有这个空检查(我想避免)并且我非常有信心有一些设计模式可以解决这个问题。我只是不记得是哪一个......

5 个答案:

答案 0 :(得分:2)

怎么样:

Preference getPreference(User user, Preference.Type type) {

    Preference preference = getUserPreferenceFor(user, type);
    if (preference == null) {
        preference = getGroupPreferenceFor(user, type);
        if (preference == null) {
           preference = getSystemPreferenceFor(user, type);
        }
    }
    return preference;
}

它仍然使用if,但看起来很优雅。

答案 1 :(得分:1)

我会尝试使用代表团(注意:许多人说代表团有性能影响,但你需要自己测量才能找到真相)。请注意它可能无法编译,因为自从上次使用java以来​​已经很久了。

public interface PreferenceGetter{
    Preference get();
}

public Preference getPreferenceIfNull(Preference pref, PreferenceGetter func) {
    if(pref == null){
        return func.get();
    }
    else{
        return pref;
    }
}

public Preference getPreference(User user, Preference.Type type){
    Preference preference = getUserPreferenceFor(user, type);
    preference = getPreferenceIfNull(preference, new PreferenceGetter(){
            public Preference get(){
                getGroupPreferenceFor(user, type);
            }
        });
    preference = getPreferenceIfNull(preference, new PreferenceGetter(){
            public Preference get(){
                getSystemPreferenceFor(user, type);
            }
        });
    return preference
}

<强>更新

有一种替代使用Decorator模式而不是委托(如ArtemStorozhuk所建议的那样)。由于参数传递的能力,最好在C#中使用委托而不是Decorator,但可能在java中有所不同。而且,Decorator更难理解。

public interface PreferenceGetter{
    Preference get(Preference pref, PreferenceGetter func);
}

public class NullPreferenceGetter implements PreferenceGetter{
    public Preference get(Preference pref, PreferenceGetter func){
        return null;
    }
}

public class UserPreferenceGetter implements PreferenceGetter{
    public UserPreferenceGetter(PreferenceGetter decorated){
         this.decorated = decorated;
    }
    private PreferenceGetter decorated;
    public Preference get(Preference pref, PreferenceGetter func){
        Preference result = getUserPreferenceFor(user, type);
        if(result == null){
            result = decorated.get(pref, func);
        }
        return result;
    }
}

public class GroupPreferenceGetter implements PreferenceGetter{
    public GroupPreferenceGetter(PreferenceGetter decorated){
         this.decorated = decorated;
    }
    private PreferenceGetter decorated;
    public Preference get(Preference pref, PreferenceGetter func){
        Preference result = getGroupPreferenceFor(user, type);
        if(result == null){
            result = decorated.get(pref, func);
        }
        return result;
    }
}

用法:

public Preference getPreference(User user, Preference.Type type){
    PreferenceGetter getter = new UserPreferenceGetter(
        new GroupPreferenceGetter(
            new SystemPreferenceGetter(
                new NullPreferenceGetter())
            )
        );
    return getter.get(user, type);
}

答案 2 :(得分:0)

我将使用不同的Provider实现继续您的第二个想法,但是为每个Provider添加第二个方法,可以用来确定它是否可以提供值。然后,您可以使用该方法而不是检查null返回值,如下所示:

for (PreferenceProvider provider : providers) {
    if (provider.canProvideAPreferenceFor(user, type)) {
        return provider.getUserPreferenceFor(user, type);
    }
}

return null;

答案 3 :(得分:0)

您可以使用给定的一组首选项使Preferences类可变。

Preference getPreference(User user, Preference.Type type) {

    Preference preference = new Preference( getSystemPreferenceFor(user, type) );

    preference.merge( getGroupPreferenceFor(user, type) );
    preference.merge( getUserPreferenceFor(user, type) );

    return preference;

}

现在merge必须检查null,但仅限于单个实例。如果合适,Preference.Preference()可以默认为getSystemPreference。

这确实改变了仅使用一组首选项的前提。

答案 4 :(得分:0)

我建议使用wrapper (decorator)模式来执行此操作。

您只需将每个支票包装到一个对象中,然后创建就绪装饰对象。维基百科有一个使用它的好例子。

祝你好运。