Raj*_*ran 5 java oop design-patterns
因此,类似类型的问题在其他地方得到了回答,但在这里我期待在给定情况下省略 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));
}
}
Run Code Online (Sandbox Code Playgroud)
其中所有视图模型都扩展一个名为 的类ReceiptViewModel。例如
public class HotelReceiptViewModel extends ReceiptViewModel implements ViewModel {
public HotelReceiptViewModel(Receipt receipt) {
super(receipt);
this.receiptNumber = receipt.getDocumentNumber();
this.receiptHeading = "HOTEL";
}
}
Run Code Online (Sandbox Code Playgroud)
目前有5种收据类型,未来将增加3-4种收据类型。
可能的解决方案
HashMapEnum让我们看看每种方法的优缺点
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());
}
Run Code Online (Sandbox Code Playgroud)
课程ReceiptViewModel看起来像
public class HotelReceiptViewModel extends ReceiptViewModel implements ViewModel {
public HotelReceiptViewModel(Receipt receipt) {
super(receipt);
this.receiptNumber = receipt.getDocumentNumber();
this.receiptHeading = "HOTEL";
}
}
Run Code Online (Sandbox Code Playgroud)
优点 更快、更简单、可扩展。
CONS
对象在构造函数中ReceiptViewModel不需要类型的对象。而是使用 setter 进行设置,初始化类的所有逻辑现在都将移动。ReceiptReceiptReceiptViewModel
2. 枚举的使用
private ReceiptViewModel getViewModel(Receipt receipt) {
String receiptType = receipt.type;
ReceiptViewModel viewModel =
ReceiptViewModels.valueOf(receiptType).getReceiptViewModel(receipt);
return viewModel;
}
Run Code Online (Sandbox Code Playgroud)
枚举看起来像
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);
}
Run Code Online (Sandbox Code Playgroud)
优点 快速,可能很简单。
缺点 枚举的大小将随着收据类型的增加而不断增加,导致代码不可维护。
ReceiptViewModels.valueOf(receiptType)需要已知的收据类型。如果新的收据类型作为来自服务器的响应,则会导致IllegalArgumentException
3.反射的使用
Class<? extends ReceiptViewModel> viewModel = Class.
forName(receiptType + name + "ReceiptViewModel").asSubclass(ReceiptViewModel.class);
ReceiptViewModel receiptViewModel = viewModel .newInstance();
Run Code Online (Sandbox Code Playgroud)
缺点 1. 速度较慢
类名不同时不能使用。例如,对于 LUNCH 类型,视图模型类名称为 FoodReceiptViewModel
从收据获取值的逻辑被移至 setter,而不是像 HashMap 那样的构造函数
优点易于理解且比反射更快
缺点可能有点矫枉过正。将为每种类型的收据添加一个新类别。
考虑到上述所有要点,对于我的用例来说,哪种方法是删除多个 if-else 块的最佳方法?
我会使用开关,除非有理由使用更复杂的东西。
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);
}
Run Code Online (Sandbox Code Playgroud)
我认为这是最好的解决方案,因为它是满足您需求的最简单的解决方案。