所以相似类型的问题在其他地方得到解答,但在这里我期待在给定情况下省略if else链的最佳方法。
当前代码
private ViewModel getViewModel(Receipt receipt) {
String receiptType = receipt.type;
if(receiptType.equals("HOTEL")) {
return new HotelReceiptViewModel(receipt));
} else if(receiptType.equals("CAR")) {
return new CarReceiptViewModel(receipt));
}
.
.
.
} else if(receiptType.equals("LUNCH")) {
return new FoodReceiptViewModel(receipt));
}
}
其中所有视图模型都扩展了一个名为ReceiptViewModel
的类。 e.g。
public class HotelReceiptViewModel extends ReceiptViewModel implements ViewModel {
public HotelReceiptViewModel(Receipt receipt) {
super(receipt);
this.receiptNumber = receipt.getDocumentNumber();
this.receiptHeading = "HOTEL";
}
}
目前有5种类型的收据,将来还会有3-4种收据。
可能的解决方案
HashMap
Enum
让我们看看每种方法的优缺点
1。使用HashMap
private ReceiptViewModel getViewModel(Receipt receipt) {
Map<String, ReceiptViewModel> map = getViewModelsMap();
String receiptType = receipt.type;
ReceiptViewModel viewModel = map.get(receiptType);
if(viewModel != null) {
viewModel.setReceipt(receipt);
}
return viewModel;
}
private Map<String, ReceiptViewModel> getViewModelsMap() {
Map<String, ReceiptViewModel> map = new HashMap<String, ReceiptViewModel>();
map.add("HOTEL"), new HotelReceiptViewModel());
map.add("CAR"), new CarReceiptViewModel());
map.add("LUNCH"), new FoodReceiptViewModel());
}
和ReceiptViewModel
类看起来像
public class HotelReceiptViewModel extends ReceiptViewModel implements ViewModel {
public HotelReceiptViewModel(Receipt receipt) {
super(receipt);
this.receiptNumber = receipt.getDocumentNumber();
this.receiptHeading = "HOTEL";
}
}
赞成 更快,更容易,更可扩展。
CONS
ReceiptViewModel
对象在构造函数中不需要Receipt
类型的对象。使用setter设置Receipt
,其中初始化ReceiptViewModel
类的所有逻辑现在都将移动。
2。使用枚举
private ReceiptViewModel getViewModel(Receipt receipt) {
String receiptType = receipt.type;
ReceiptViewModel viewModel =
ReceiptViewModels.valueOf(receiptType).getReceiptViewModel(receipt);
return viewModel;
}
Enum看起来像
public enum ReceiptViewModels {
HOTEL(
ReceiptViewModel getReceiptViewModel(Receipt receipt) {
return new HotelReceiptViewModel(receipt);
}
),
CAR(
ReceiptViewModel getReceiptViewModel(Receipt receipt) {
return new CarReceiptViewModel(receipt);
}
),
.
.
.
LUNCH(
ReceiptViewModel getReceiptViewModel(Receipt receipt) {
return new FoodReceiptViewModel(receipt);
}
),
public abstract ReceiptViewModel getReceiptViewModel(Receipt receipt);
}
赞成 快,可能很容易。
CONS 随着收据类型的增加,Enum的大小将继续增加,导致代码不可维护。
ReceiptViewModels.valueOf(receiptType)
需要已知的收据类型。如果新收据类型作为来自服务器的响应,则会生成IllegalArgumentException
第3。使用反思
Class<? extends ReceiptViewModel> viewModel = Class.
forName(receiptType + name + "ReceiptViewModel").asSubclass(ReceiptViewModel.class);
ReceiptViewModel receiptViewModel = viewModel .newInstance();
CONS 1.较慢
当班级名称不同时,不能使用。例如对于LUNCH类型,视图模型类名称为FoodReceiptViewModel
从收据中获取值的逻辑被移动到setter而不是构造函数,就像HashMap一样
4。使用Strategy Pattern或Template Pattern
PROS 易于理解,比反思更快
CONS 可能是一种矫枉过正。将为每种收据添加一个新类。
考虑以上所有要点,这是我的用例删除多个if-else块的最佳方法?
答案 0 :(得分:2)
我会使用开关,除非有理由使用更复杂的东西。
private ViewModel getViewModel(Receipt receipt) {
switch(receipt.type) {
case "HOTEL": return new HotelReceiptViewModel(receipt);
case "CAR": return new CarReceiptViewModel(receipt);
case "LUNCH": return new FoodReceiptViewModel(receipt);
default:
throw new IllegalArgumentException("Unknown receipt type " + receipt.type);
}
我认为这是最好的解决方案,因为它是最简单的,满足您的需求。
答案 1 :(得分:1)
不需要任何行为,不需要任何结构,也不需要多态,所以我没有兴趣使用策略等设计模式,或者使用一个只会带来复杂性的地图。 你想要一个非常简单的状态机。所以,“if else if”或“switch”是完美的。 也许在主题之外但是使用私有方法,代码不是单一可测试的。
答案 2 :(得分:0)
我会在你的Receipt
课程中创建一个新的抽象方法。像
public <T extends ReceiptViewModel> T createModel()
然后创建Receipt
类的子类,其中每个type
对应一个子类。然后每个子类将实现自己的createModel
版本,返回ReceiptViewModel
的正确子类。您的初始代码将像
private ViewModel getViewModel(Receipt receipt) {
return receipt.createModel()
}