Interfaces, Abstract Classes and Polymorphism
13.1 Interfaces
interface Shape
{
double area();
final string describe() { import std.conv; return "Area: " ~ area().to!string; } // final method with a body
static Shape unit() { return new Square(1); }
}
interface Named { string name(); }
class Square : Shape, Named
{
double side;
this(double s) { side = s; }
double area() { return side * side; }
string name() { return "square"; }
}
Shape[] shapes = [new Square(2), Shape.unit()];
foreach (s; shapes) writeln(s.describe);13.2 Abstract Classes
abstract class Vehicle
{
abstract void drive(); // must be implemented
void honk() { writeln("Beep"); }
}
class Car : Vehicle { override void drive() { writeln("Driving"); } }13.3 Static (Compile-Time) Polymorphism
Prefer templates/ranges for performance-critical polymorphism (no virtual calls). Use interfaces for runtime polymorphism and plugins.
// Duck typing with templates: any type with area() works
double totalArea(T)(T[] items) { double t = 0; foreach (i; items) t += i.area; return t; }13.4 Design Patterns in D
Singleton (static this / lazy thread-safe init), Factory (Object.factory("module.ClassName")), Visitor (via templates and overloads), Observer (delegates/signals: std.signals), Strategy (delegates), RAII (structs with destructors).