Thinking about misusing sealed classes, let's look at the following design.
There are two modules:
parser
(Kotlin) - is responsible for making instances from Stringprocessor
(Java) - pumps over raw incoming data into a strongly typed storage (i.e. relational tables)
- String comes from external source to
processor
processor
delegates its recognition toparser
parser
makes instances of different types[Banana, Nail, Shoe]
based on somerules X
processor
persists each instance into an appropriate table based on somerules Y
Is it appropriate to use sealed classes here like this in parser
and after that in processor
make decisions base on concrete type of each instance?
// 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())
}
}
I see that something is wrong in this approach, because growing number of Item's subclasses could lead to a design catastrophe, but cannot figure out whether is there a "canonical" use case of sealed classes sufficiently different from this one.
What is the limit of sealed classes applicability, when system designer should prefer something "less typed" like the following:
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
}
}
Aucun commentaire:
Enregistrer un commentaire