I am using an external API, which I cannot modify and want to access a field on an object that is not defined by its interface.
Interface IFoo
does not define the field headers
.
Both Foo
and Bar
implement IFoo
and both have an additional field headers
of type String
.
This is working in Dart, but is far from elegant:
void doSomething (IFoo data) {
String headers;
if (data is Foo) {
headers = data.headers;
} else if (data is Bar) {
headers = data.headers;
}
}
This does not work in dart:
void doSomething (IFoo data) {
String headers;
if (data is Foo || data is Bar) {
headers = data.headers;
}
}
Is there a more elegant way than the above first example?
Is there a more elegant way than the above first example?
Taking a look at a higher level of the whole picture, the "elegant way" that I'd suggest in this case is following the Interface Segregation Principle.
It's clear that the declaration of the headers
property is common for some of the types (such as Foo
and Bar
), however, if declaring it in IFoo
does not make sense (for code design reasons, such as there are other types of IFoo
don't need to have the headers
declared), it's still sensible to have a common type for all subtypes that have the headers
property.
In Dart, using mixin would be a proper way to achieve it. Example:
abstract class IFoo {}
mixin MixinFoo {
String get headers => 'MixinFoo';
}
class Foo with MixinFoo implements IFoo {
@override
String get headers => 'Foo';
}
class Bar with MixinFoo implements IFoo {
@override
String get headers => 'Bar';
}
Note that Foo
and Bar
are still IFoo
types, additionally, they are MixinFoo
as well! This means that they have the headers
property without mixing the logic of being IFoo
s.
Therefore, you are able to cast the given value, as:
void doSomething (IFoo data) {
String headers;
MixinFoo? dataMixin = (data is MixinFoo ? data : null) as MixinFoo?;
// if the data is not a MixinFoo, then dataMixin will be null
if (dataMixin != null) {
headers = dataMixin.headers;
}
}
Or (since we are talking about an "elegant way" 🙂):
void doSomething (IFoo data) {
try {
String headers;
final dataMixin = data as MixinFoo;
headers = dataMixin.headers;
}
on TypeError catch(_) {
// fallback, if the data is not a MixinFoo...
}
}
Any MixinFoo
type will be castable now, it makes more sense from a code design perspective.