考虑到误用密封类,我们来看看下面的设计。
有两个模块:
parser
(Kotlin) - 负责从 String 创建实例processor
(Java) - 将原始传入数据泵入强类型存储(即关系表)
- 字符串来自外部源
processor
processor
将其认可委托给parser
parser
[Banana, Nail, Shoe]
根据一些创建不同类型的实例rules X
processor
根据某些情况将每个实例持久保存到适当的表中rules Y
在基于每个实例的具体类型做出决策时parser
,是否适合在这里使用密封类?processor
// parser module exposes Item and its subclasses
sealed interface Item {
class Banana(/*state 1*/) : Item
class Nail(/*state 2*/) : Item
class Shoe(/*state 3*/) : Item
}
fun parse(value: String, rule: ParseRule): Item {
return when (true) {
rule.canParseBanana(value) -> rule.makeBananaFrom(value)
rule.canParseNail(value) -> rule.makeNailFrom(value)
rule.canParseShoe(value) -> rule.makeShoeFrom(value)
else -> throw RuntimeException("cannot parse")
}
}
// processor module makes decisions based on class
void process(String value){
Item item = parser.parse(value);
if (item instance of Item.Banana){
persistBanana((Item.Banana) item)
} else if ( ... )
// etc
} else {
throw new RuntimeException("Unknown subclass of Item : " + item.getClass())
}
}
我发现这种方法有问题,因为越来越多的 Item 子类可能会导致设计灾难,但无法弄清楚是否存在与此完全不同的密封类的“规范”用例。
什么是密封类适用性的限制,当系统设计者应该更喜欢“较少类型”的东西时,如下所示:
class Item{
Object marker; // String or Enum
Map<String, Object> attributes;
}
// basically it is the same, but without dancing with types
void process(String value){
Item item = parser.parse(value);
if ("BANANA".equals(item.marker)){
persistBanana(item.attributes)
} else if (...){
// etc
}
}