From d0a230b73ae35935e50fe65c27abe559127238b6 Mon Sep 17 00:00:00 2001 From: Phong Nguyen Date: Sat, 22 Nov 2025 21:59:42 +0700 Subject: [PATCH 1/2] Add templatemethod pattern --- CMakeLists.txt | 1 + ...ttern_behavioral_templatemethod.drawio.svg | 4 + src/patterns/behavioral/TemplateMethod.cpp | 125 ++++++++++++++++++ 3 files changed, 130 insertions(+) create mode 100644 docs/uml/pattern_behavioral_templatemethod.drawio.svg create mode 100644 src/patterns/behavioral/TemplateMethod.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index c5e5f1f..b5c1be4 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -104,6 +104,7 @@ set(APP_SOURCES "src/patterns/behavioral/Mediator.cpp" "src/patterns/behavioral/Memento.cpp" "src/patterns/behavioral/Visitor.cpp" + "src/patterns/behavioral/TemplateMethod.cpp" ) # Test files diff --git a/docs/uml/pattern_behavioral_templatemethod.drawio.svg b/docs/uml/pattern_behavioral_templatemethod.drawio.svg new file mode 100644 index 0000000..d5d71ce --- /dev/null +++ b/docs/uml/pattern_behavioral_templatemethod.drawio.svg @@ -0,0 +1,4 @@ + + + +
main:
{
AbstractClass* clazz1 = new ConcreteClass1();
clientCode(clazz1);

AbstractClass* clazz2 = new ConcreteClass2();
clientCode(clazz2);
}

clientCode:
{
 clazz->templateMethod();
}
Client
+ clientCode(AbstractClass* clazz): type
<<Abstract>>
AbstractClass
+ field: type
+ templateMethod(type): type
# baseMethod(type): type

# hookMethod(type): type
# abstractMethod(type): type
ConcreteClass1
+ field: type
# abstractMethod(type): type
ConcreteClass2
+ field: type
# hookMethod(type): type
# abstractMethod(type): type

templateMedthod:
{
 this->baseMethod();
 this->hookMethod();
 this->abstractMethod();
}
baseMethod:
{
 // do some base logics
}
hookMethod:
{
// default
}
abstract: 
virtual void abstractMethod() = 0;
Extends
Extends
\ No newline at end of file diff --git a/src/patterns/behavioral/TemplateMethod.cpp b/src/patterns/behavioral/TemplateMethod.cpp new file mode 100644 index 0000000..6c21183 --- /dev/null +++ b/src/patterns/behavioral/TemplateMethod.cpp @@ -0,0 +1,125 @@ +// cppcheck-suppress-file [functionStatic] + +// is a behavioral design pattern that defines the skeleton of an algorithm in the `superclass` +// but lets `subclasses` override specific steps of the algorithm without changing its structure. +// Appicability: +// (*) when you want to let clients extend only particular steps of an algorithm, but not the whole algorithm or its structure. +// (**) when you have several classes that contain almost identical algorithms with some minor differences. +// As a result, you might need to modify all classes when the algorithm changes. +// (**) when a behavior makes sense only in some classes of a class hierarchy, but not in others. +// UML: docs/uml/patterns_behavioral_visitor.drawio.svg + +#include +#include +#include + +namespace +{ + namespace TemplateMethod + { + class AbstractClass + { + public: + virtual ~AbstractClass() = default; + // Template Method (non-virtual => cannot be overridden) + // Defines the algorithm's skeleton and ensures subclasses cannot change the flow. + void templateMethod() const + { + baseOperation1(); + abstractMethod1(); + hookOperation1(); + + baseOperation2(); + abstractMethod2(); + hookOperation2(); + } + + protected: + // 1. Base operations: These have full implementations and cannot be overridden. + void baseOperation1() const + { + // Common logic step 1 + std::cout << "[AbstractClass]\t Executed base operation - 1\n"; + } + + void baseOperation2() const + { + // Common logic step 2 + std::cout << "[AbstractClass]\t Executed base operation - 2\n"; + } + + // 2. Hook methods: Subclasses may override them to extend behavior, but overriding is optional. + virtual void hookOperation1() const {} + virtual void hookOperation2() const {} + + // 3. Abstract methods: Subclasses MUST provide implementations. + virtual void abstractMethod1() const = 0; + virtual void abstractMethod2() const = 0; + }; + + class ConcreteClass1 : public AbstractClass + { + public: + void abstractMethod1() const override + { + std::cout << "[ConcreteClass1]\t Implemented Operation - 2\n"; + } + + void abstractMethod2() const override + { + std::cout << "[ConcreteClass1]\t Implemented Operation - 2\n"; + } + + void hookOperation1() const override + { + std::cout << "[ConcreteClass1]\t Overridden Hook - 1\n"; + } + }; + + class ConcreteClass2 : public AbstractClass + { + public: + void abstractMethod1() const override + { + std::cout << "[ConcreteClass2]\t Implemented Operation - 2\n"; + } + + void abstractMethod2() const override + { + std::cout << "[ConcreteClass2]\t Implemented Operation - 2\n"; + } + }; + + namespace Client + { + void clientCode(const AbstractClass *clazz) + { + clazz->templateMethod(); + } + } + void run() + { + std::cout << "\t[ConcreteClass1] Executed templateMethod\n"; + AbstractClass *clazz1 = new ConcreteClass1(); + Client::clientCode(clazz1); + + std::cout << "\t[ConcreteClass1] Executed templateMethod\n"; + AbstractClass *clazz2 = new ConcreteClass2(); + Client::clientCode(clazz2); + + delete clazz1; + delete clazz2; + } + } +} + +struct TemplateMethodAutoRunner +{ + TemplateMethodAutoRunner() + { + std::cout << "\n--- TemplateMethod Pattern Example ---\n"; + TemplateMethod::run(); + } +}; + +static TemplateMethodAutoRunner instance; \ No newline at end of file From ef94911be9099d7d37f4bedc13428fafd7aa089e Mon Sep 17 00:00:00 2001 From: Phong Nguyen Date: Sat, 22 Nov 2025 22:02:32 +0700 Subject: [PATCH 2/2] fix doc issue --- src/patterns/behavioral/TemplateMethod.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/patterns/behavioral/TemplateMethod.cpp b/src/patterns/behavioral/TemplateMethod.cpp index 6c21183..87a2d32 100644 --- a/src/patterns/behavioral/TemplateMethod.cpp +++ b/src/patterns/behavioral/TemplateMethod.cpp @@ -7,11 +7,9 @@ // (**) when you have several classes that contain almost identical algorithms with some minor differences. // As a result, you might need to modify all classes when the algorithm changes. // (**) when a behavior makes sense only in some classes of a class hierarchy, but not in others. -// UML: docs/uml/patterns_behavioral_visitor.drawio.svg +// UML: docs/uml/patterns_behavioral_templatemethod.drawio.svg #include -#include -#include namespace {