Created
July 4, 2019 04:16
-
-
Save run-dlang/bfc043093066da04f0d2bec5a07de459 to your computer and use it in GitHub Desktop.
Code shared from run.dlang.io.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import std.stdio, std.traits; | |
struct ModelA | |
{ | |
class Animal | |
{ | |
void Attack(Animal who) { writeln(Name, " is attacking ", who.Name, "!"); } | |
string Type() { return "Unknown Animal Type"; } | |
string Name() { return "Unknown Animal"; } | |
Food LikesWhichFood() { writeln("Food D Type: ", fullyQualifiedName!Food); return null; } | |
} | |
class Cat : Animal | |
{ | |
string name = "Unknown Cat"; | |
override string Type() { return "Cat"; } | |
override string Name() { return name; } | |
void Meow() { writeln("Meow!"); } | |
this() { } | |
this(string n) { name = n; } | |
} | |
class Dog : Animal | |
{ | |
string name = "Unknown Dog"; | |
override string Type() { return "Dog"; } | |
override string Name() { return name; } | |
void Bark() { writeln("Bark!"); } | |
this() { } | |
this(string n) { name = n; } | |
} | |
class Food | |
{ | |
} | |
} | |
struct ModelB | |
{ | |
class Animal : ModelA.Animal | |
{ | |
} | |
class Cat : ModelA.Cat | |
{ | |
override Food LikesWhichFood() { writeln("Food D Type: ", fullyQualifiedName!Food); return new Cabbage; } | |
this() { } | |
this(string n) { name = n; } | |
} | |
class Dog : ModelA.Dog | |
{ | |
override Food LikesWhichFood() { writeln("Food D Type: ", fullyQualifiedName!Food); return new Donuts; } | |
this() { } | |
this(string n) { name = n; } | |
} | |
class Food : ModelA.Food | |
{ | |
void IsItTasty() { writeln("Unknown Food"); } | |
} | |
class Donuts : Food | |
{ | |
override void IsItTasty() { writeln("YUK!"); } | |
} | |
class Cabbage : Food | |
{ | |
override void IsItTasty() { writeln("YUM!"); } | |
} | |
} | |
void main() | |
{ | |
{ | |
auto animal1 = new ModelA.Cat("Mittens"); | |
auto animal2 = new ModelA.Dog("Sparky"); | |
writeln(animal1.Name); | |
writeln(animal2.Name); | |
animal1.Attack(animal2); | |
animal1.LikesWhichFood; | |
} | |
writeln("\n----------\n"); | |
{ | |
auto animal1 = new ModelB.Cat("Super Mittens"); | |
auto animal2 = new ModelB.Dog("Super Sparky"); | |
writeln(animal1.Name); | |
writeln(animal2.Name); | |
animal1.Attack(animal2); | |
auto f = animal1.LikesWhichFood; | |
f.IsItTasty; // Error: no property `IsItTasty` for type `Models.ModelA.iFood`. It should return a ModelB.iFood, we are inside ModelB, never any risk | |
(cast(ModelB.Food)f).IsItTasty; // We can, of course, force it, but that is the rub, we don't have to, that is why we want to have a concept of a model, it tells the compiler that there is something more going on and it can reduce all this overhead. We can't even override this because of the contravariance rule. | |
} | |
writeln("\n----------\n"); | |
// This is the magic, ModelB is now substituted in Model A. It's basically still oop but our entire derived model is(or should be) used. | |
// We can substitute the new model in all places where the old was used. This is the easy way to do ModelViewModel, we simply extend the model and add the view, no complex bridging, adapting, maintance, dependencies, etc. | |
{ | |
auto animal1 = new ModelB.Cat("Super Mittens"); | |
auto animal2 = new ModelB.Dog("Super Sparky"); | |
writeln(animal1.Name); | |
writeln(animal2.Name); | |
animal1.Attack(animal2); | |
animal1.LikesWhichFood; | |
auto f = animal2.LikesWhichFood; | |
f.IsItTasty; // This Error is ok, we are inside ModelA, ModelA would never use IsItTasty and it would be wrong to do so(it's only wrong because it should be impossible for ModelA to know about ModelB, else we create a dependency between models and really end up with one combined model rather than two separate models). But note that we could cast | |
(cast(ModelB.Food)f).IsItTasty; // We can, of course, force it though(only because we know for a fact we are actually dealing with a ModelB disugised as a ModelA, this is generally not the case), but this then shows a dependency. Note that it is exactly like the above model though... but there is a huge difference. In the first case it is afe, in this case it is not.. and the only difference is the model we are working in. | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment