The Final Bird Design: The Full Code
The complete, final version of the Bird design from this series, browsable file by file, exactly as it would sit in a real codebase.
The full evolution walked through every version of this design, one principle at a time. This post is the reference: the final version, as real files in a real folder, in all four languages, compiled and run to make sure every piece actually works together.
The folder layout separates contracts from implementations: every interface (Flyable, Eater, NonFlyable, FlyingBehavior) lives under bird/interfaces/, and every class (Bird and every concrete bird) lives under bird/classes/. The three flying-behavior implementations keep their own flying-behaviors/ subfolder inside classes/, since that trio only ever serves each other.
bird/classes/flying-behaviors/ folder, Java's copy of that same folder is named bird/classes/flyingbehaviors/. Same code, same reason for existing, just a naming rule Java forces on you that the others don't.#include <iostream>
#include <memory>
#include "bird/classes/Bird.h"
#include "bird/interfaces/Flyable.h"
#include "bird/interfaces/NonFlyable.h"
#include "bird/classes/flying-behaviors/CrowOwlFlyingBehavior.h"
#include "bird/classes/flying-behaviors/ParrotSparrowFlyingBehavior.h"
#include "bird/classes/flying-behaviors/PigeonFlyingBehavior.h"
#include "bird/classes/Crow.h"
#include "bird/classes/Owl.h"
#include "bird/classes/Parrot.h"
#include "bird/classes/Sparrow.h"
#include "bird/classes/Pigeon.h"
#include "bird/classes/Penguin.h"
int main() {
// Dependency injection: each bird is handed its flying behavior, it never creates one itself.
Crow crow("Crow", "black", 2, std::make_unique<CrowOwlFlyingBehavior>());
Owl owl("Owl", "brown", 3, std::make_unique<CrowOwlFlyingBehavior>());
Parrot parrot("Parrot", "green", 1, std::make_unique<ParrotSparrowFlyingBehavior>());
Sparrow sparrow("Sparrow", "brown", 1, std::make_unique<ParrotSparrowFlyingBehavior>());
Pigeon pigeon("Pigeon", "grey", 2, std::make_unique<PigeonFlyingBehavior>());
Penguin penguin("Penguin", "black-and-white", 4);
Bird* allBirds[] = { &crow, &owl, &parrot, &sparrow, &pigeon, &penguin };
for (Bird* bird : allBirds) {
bird->walk();
}
// Flyable* is the single type that means "every bird that can fly", nothing else.
Flyable* fliers[] = { &crow, &owl, &parrot, &sparrow, &pigeon };
for (Flyable* bird : fliers) {
bird->fly();
}
// NonFlyable* is the marker-interface counterpart, only needed because this demo asks for it.
NonFlyable* groundedBirds[] = { &penguin };
std::cout << (sizeof(groundedBirds) / sizeof(groundedBirds[0])) << " bird(s) grounded.\n";
crow.eat();
pigeon.eat();
// Swapping Crow to fly like a parrot needs zero changes inside the Crow class itself.
Crow crowFlyingLikeAParrot("Crow", "black", 2, std::make_unique<ParrotSparrowFlyingBehavior>());
crowFlyingLikeAParrot.fly();
return 0;
}Keep reading