Reputation: 1296
I recently came across the title of this question while studying Dart Apprentice but I couldn't find anything related to the dart language. I understand how conditionals work and while I have a fair knowledge of OOP, I understand how polymorphism works. But I can't see the relationship between conditionals and polymorphism or how one can replace conditionals with polymorphism. Can anyone help clarify?
Upvotes: 1
Views: 421
Reputation: 71803
My best guess is that it means that instead of doing conditional checks on objects to decide what to do with them, as you typically would in a static helper function, you should instead rely on virtual method dispatch.
That means doing dynamic dispatch using the virtual method invocation functionality, instead of doing it manually using is
tests.
Example: Here we have an recursive data structure, representing JSON data.
abstract class JsonData {}
class JsonValue<T> extends JsonData {
final T value;
JsonValue(this.value);
}
class JsonList extends JsonData {
final List<JsonData> _elements;
JsonList(List<JsonData> elements) : _elements = elements;
int get length => _elements.length;
JsonData operator[](int index) => _elements[index];
}
class JsonMap extends JsonData {
final Map<String, JsonData> _map;
JsonMap(Map<String, JsonData> map) : _map = map;
Iterable get keys => _map.keys;
JsonData operator[](String key) =>
_map[key] ?? (throw ArgumentError.value(key, "key", "No entry"));
}
An example object graph could be:
var data = JsonMap({
"first": JsonList([JsonValue(1), JsonValue("ok")]),
"second": JsonValue(false),
});
Now, if I wanted to figure out whether a particular string occurs in the JsonData
, either as a map key or as a value, I could write something like:
bool containsString(JsonData json, String text) {
if (json is JsonValue) {
return text == json.value;
} else if (json is JsonList) {
for (i = 0; i < json.length; i++) {
if (containsString(json[i], text)) return true;
}
return false;
} else if (json is JsonMap) {
for (var key in json.keys) {
if (text == key) return true;
if (containsString(json[key], text)) return true;
}
return false;
} else {
throw UnsupportedError("Unexpected JSON value");
}
}
However, it is better to put the specialized functionality into the classes themselves, changing the classes to:
abstract class JsonData {
bool containsString(String text);
}
class JsonValue<T> extends JsonData {
final T value;
JsonValue(this.value);
bool containstString(String text) => text == value;
}
class JsonList extends JsonData {
final List<JsonData> _elements;
JsonList(List<JsonData> elements) : _elements = elements;
int get length => _elements.length;
JsonData operator[](int index) => _elements[index];
bool containsString(String text) {
for (var element in elements) {
if (element.containsString(text)) return true;
}
return false;
}
}
class JsonMap extends JsonData {
final Map<String, JsonData> _map;
JsonMap(Map<String, JsonData> map) : _map = map;
Iterable get keys => _map.keys;
JsonData operator[](String key) =>
_map[key] ?? (throw ArgumentError.value(key, "key", "No entry"));
bool containsString(String text) {
for (var entry in _map.entries) {
if (text == entry.key || entry.value.containsString(text)) {
return true;
}
}
return false;
}
}
Using this approach is better for a number of reasons:
Upvotes: 1