Skip to content

Commit 21cde83

Browse files
author
XuhuaHuang
committed
Add design principle examples
1 parent 2ee70e3 commit 21cde83

File tree

9 files changed

+528
-25
lines changed

9 files changed

+528
-25
lines changed

DesignPrinciple/CMakeLists.txt

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
cmake_minimum_required(VERSION 3.20)
2+
3+
project("design_principle" LANGUAGES CXX)
4+
5+
set(CMAKE_CXX_STANDARD 23)
6+
set(CMAKE_CXX_STANDARD_REQUIRED ON)
7+
8+
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
9+
10+
add_executable(composition_over_inheritance "composition_over_inheritance.cpp")
11+
add_executable(interface_segregation "interface_segregation.cpp")
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
#include <iostream>
2+
#include <memory>
3+
#include <string>
4+
5+
class ILogger {
6+
public:
7+
virtual ~ILogger() = default;
8+
virtual void log(const std::string& msg) const = 0;
9+
};
10+
11+
class FileLogger : public ILogger {
12+
public:
13+
void log(const std::string& msg) const override { std::cout << "[File] " << msg << '\n'; }
14+
};
15+
16+
class ConsoleLogger : public ILogger {
17+
public:
18+
void log(const std::string& msg) const override { std::cout << "[Console] " << msg << '\n'; }
19+
};
20+
21+
class Application {
22+
public:
23+
explicit Application(std::unique_ptr<ILogger> logger_in)
24+
: logger(std::move(logger_in)) {}
25+
26+
void run() const { logger->log("App is running"); }
27+
28+
private:
29+
std::unique_ptr<ILogger> logger;
30+
};
31+
32+
int main() {
33+
std::unique_ptr<ILogger> logger = std::unique_ptr<ILogger>(new ConsoleLogger());
34+
35+
Application app(std::move(logger));
36+
app.run();
37+
return 0;
38+
}
Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
/**
2+
* @file composition_over_inheritance.cpp
3+
* @author Xuhua Huang
4+
* @brief Inheritance establishes an IS-A relaHonship
5+
* Composition/aggregation establish a HAS-A relaHonship – this can often be preferable
6+
*
7+
* Aggregation
8+
* An object comprised of other objects uses those objects
9+
* Those objects exist outside of the object
10+
* When the object is destroyed, the objects that comprise it remain
11+
*
12+
* @version 0.1
13+
* @date 2026-04-09
14+
*
15+
* @copyright Copyright (c) 2026
16+
*
17+
*/
18+
19+
#include <iostream>
20+
#include <memory>
21+
// #include <string>
22+
23+
class IMovement {
24+
public:
25+
virtual ~IMovement() = default;
26+
virtual void move() const = 0;
27+
};
28+
29+
class IPowerSource {
30+
public:
31+
virtual ~IPowerSource() = default;
32+
virtual void supply_power() const = 0;
33+
};
34+
35+
class WheelMovement : public IMovement {
36+
public:
37+
void move() const override { std::cout << "Moving on wheels\n"; }
38+
};
39+
40+
class FlyingMovement : public IMovement {
41+
public:
42+
void move() const override { std::cout << "Flying in the air\n"; }
43+
};
44+
45+
class GasEngine : public IPowerSource {
46+
public:
47+
void supply_power() const override { std::cout << "Supplying power from gas engine\n"; }
48+
};
49+
50+
class ElectricBattery : public IPowerSource {
51+
public:
52+
void supply_power() const override { std::cout << "Supplying power from battery\n"; }
53+
};
54+
55+
class Vehicle {
56+
public:
57+
Vehicle(std::unique_ptr<IMovement> movement, std::unique_ptr<IPowerSource> power_source)
58+
: movement(std::move(movement))
59+
, power_source(std::move(power_source)) {}
60+
61+
void operate() const {
62+
power_source->supply_power();
63+
movement->move();
64+
}
65+
66+
private:
67+
std::unique_ptr<IMovement> movement;
68+
std::unique_ptr<IPowerSource> power_source;
69+
};
70+
71+
int main() {
72+
// Traditional car
73+
Vehicle car(std::make_unique<WheelMovement>(), std::make_unique<GasEngine>());
74+
75+
// Electric car
76+
Vehicle ev(std::make_unique<WheelMovement>(), std::make_unique<ElectricBattery>());
77+
78+
// Futuristic flying electric vehicle
79+
Vehicle drone(std::make_unique<FlyingMovement>(), std::make_unique<ElectricBattery>());
80+
81+
car.operate();
82+
ev.operate();
83+
drone.operate();
84+
}
85+
86+
class SolarPanel : public IPowerSource {
87+
public:
88+
void supply_power() const override { std::cout << "Supplying power from solar energy\n"; }
89+
};
Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
// High-level modules should not depend upon low-level modules. Both should depend upon abstractions.
2+
// Abstractions should not depend upon details. Details should depend upon abstractions.
3+
4+
/**
5+
* @file dependency_inversion.cpp
6+
* @author Xuhua Huang
7+
* @brief Demonstration of the Dependency Inversion Principle (DIP)
8+
*
9+
* High-level modules should not depend on low-level modules.
10+
* Both should depend on abstractions.
11+
*
12+
* @version 0.1
13+
* @date 2026-04-09
14+
*/
15+
16+
#include <iostream>
17+
#include <memory>
18+
#include <string>
19+
20+
// Abstractions
21+
class data_source_t {
22+
public:
23+
virtual ~data_source_t() = default;
24+
virtual std::string read() const = 0;
25+
};
26+
27+
class report_format_t {
28+
public:
29+
virtual ~report_format_t() = default;
30+
virtual void write(const std::string& data) const = 0;
31+
};
32+
33+
// Low-Level Implementations (Depend on Abstractions)
34+
class database_source_t : public data_source_t {
35+
public:
36+
std::string read() const override { return "data from database"; }
37+
};
38+
39+
class text_file_source_t : public data_source_t {
40+
public:
41+
std::string read() const override { return "data from text file"; }
42+
};
43+
44+
class html_report_writer_t : public report_format_t {
45+
public:
46+
void write(const std::string& data) const override { std::cout << "<html><body>" << data << "</body></html>\n"; }
47+
};
48+
49+
class pdf_report_writer_t : public report_format_t {
50+
public:
51+
void write(const std::string& data) const override { std::cout << "PDF Report: " << data << '\n'; }
52+
};
53+
54+
// High-Level Module (Depends Only on Abstractions)
55+
class report_generator_t {
56+
public:
57+
report_generator_t(std::unique_ptr<data_source_t> source, std::unique_ptr<report_format_t> formatter)
58+
: source(std::move(source))
59+
, formatter(std::move(formatter)) {}
60+
61+
void generate_report() const {
62+
std::string data = source->read();
63+
formatter->write(data);
64+
}
65+
66+
private:
67+
std::unique_ptr<data_source_t> source;
68+
std::unique_ptr<report_format_t> formatter;
69+
};
70+
71+
// Composition Root (Client Code)
72+
int main() {
73+
// Example 1: Database + HTML
74+
report_generator_t generator(std::make_unique<database_source_t>(), std::make_unique<html_report_writer_t>());
75+
76+
generator.generate_report();
77+
78+
std::cout << "------------------------\n";
79+
80+
// Example 2: Text File + PDF
81+
report_generator_t generator2(std::make_unique<text_file_source_t>(), std::make_unique<pdf_report_writer_t>());
82+
83+
generator2.generate_report();
84+
85+
return 0;
86+
}
Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
#include <iostream>
2+
3+
class door_t {
4+
public:
5+
virtual ~door_t() = default;
6+
7+
virtual void lock() = 0;
8+
virtual void unlock() = 0;
9+
virtual bool is_open() const = 0;
10+
};
11+
12+
class timer_client_t {
13+
public:
14+
virtual ~timer_client_t() = default;
15+
virtual void timeout() = 0;
16+
};
17+
18+
class timer {
19+
public:
20+
void register_client(timer_client_t& client, int seconds) {
21+
std::cout << "Timer started for " << seconds << " seconds\n";
22+
23+
// Simulated timeout
24+
client.timeout();
25+
}
26+
};
27+
28+
class timed_door_t : public door_t, public timer_client_t {
29+
public:
30+
void lock() override {
31+
std::cout << "Timed door locked\n";
32+
locked = true;
33+
}
34+
35+
void unlock() override {
36+
std::cout << "Timed door unlocked\n";
37+
locked = false;
38+
}
39+
40+
bool is_open() const override { return !locked; }
41+
42+
void timeout() override {
43+
std::cout << "Timed door auto-locking after timeout\n";
44+
lock();
45+
}
46+
47+
private:
48+
bool locked{true};
49+
};
50+
51+
class glass_door_t : public door_t {
52+
public:
53+
void lock() override {
54+
std::cout << "Glass door locked\n";
55+
locked = true;
56+
}
57+
58+
void unlock() override {
59+
std::cout << "Glass door unlocked\n";
60+
locked = false;
61+
}
62+
63+
bool is_open() const override { return !locked; }
64+
65+
private:
66+
bool locked{true};
67+
};
68+
69+
int main() {
70+
timer timer;
71+
72+
timed_door_t timed_door;
73+
glass_door_t glass_door;
74+
75+
timed_door.unlock();
76+
timer.register_client(timed_door, 5); // Works
77+
78+
glass_door.unlock();
79+
// timer.register_client(glass_door, 5); // ❌ compile-time error (correct!)
80+
}
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
// Subtypes must be substitutable for their base types
2+
3+
#include <iostream>
4+
#include <memory>
5+
6+
// class rectangle_t {
7+
// public:
8+
// virtual ~rectangle_t() = default;
9+
10+
// virtual void set_width(double w) { width = w; }
11+
// virtual void set_height(double h) { height = h; }
12+
13+
// double area() const { return width * height; }
14+
15+
// protected:
16+
// double width{0};
17+
// double height{0};
18+
// };
19+
20+
// class square_t : public rectangle_t {
21+
// public:
22+
// void set_width(double w) override { width = height = w; }
23+
24+
// void set_height(double h) override { width = height = h; }
25+
// };
26+
27+
class shape_t {
28+
public:
29+
virtual ~shape_t() = default;
30+
virtual double area() const = 0;
31+
};
32+
33+
class rectangle_t : public shape_t {
34+
public:
35+
rectangle_t(double w, double h)
36+
: width(w)
37+
, height(h) {}
38+
39+
double area() const override { return width * height; }
40+
41+
private:
42+
double width;
43+
double height;
44+
};
45+
46+
class square_t : public shape_t {
47+
public:
48+
explicit square_t(double side)
49+
: side(side) {}
50+
51+
double area() const override { return side * side; }
52+
53+
private:
54+
double side;
55+
};
56+
57+
void print_area(const shape_t& shape) {
58+
std::cout << "Area: " << shape.area() << '\n';
59+
}
60+
61+
int main() {
62+
rectangle_t rect(5, 10);
63+
square_t square(5);
64+
65+
print_area(rect); // OK
66+
print_area(square); // OK
67+
}

0 commit comments

Comments
 (0)