当从多个位置查询数据并且应该在第一个非空实例上返回时,有没有办法避免使用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;
}
}
}
最后一个足够接近但它仍然有这个空检查(我想避免)并且我非常有信心有一些设计模式可以解决这个问题。我只是不记得是哪一个......
答案 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)模式来执行此操作。
您只需将每个支票包装到一个对象中,然后创建就绪装饰对象。维基百科有一个使用它的好例子。
祝你好运。