Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,7 @@ set(APP_SOURCES
"src/patterns/structural/Composite.cpp"
"src/patterns/structural/Flyweight.cpp"
"src/patterns/structural/Facade.cpp"
"src/patterns/structural/Decorator.cpp"
)

# Test files
Expand Down
4 changes: 4 additions & 0 deletions docs/uml/patterns_structural_decorator.drawio.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 2 additions & 2 deletions src/patterns/structural/Composite.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
// Appicability:
// (*) when you have to implement a tree-like object structure.
// (**) when you want the client code to treat both simple and complex elements uniformly.
// UML: docs/uml/patterns_structural_facade.drawio.svg
// UML: docs/uml/patterns_structural_composite.drawio.svg

#include <iostream>
#include <string>
Expand Down Expand Up @@ -534,7 +534,7 @@ struct CompositeAutoRuner
CompositeAutoRuner()
{
std::cout << "\n--- Composite Pattern Example ---\n";
// Problem::run();
Problem::run();
CompositePattern::run();
}
};
Expand Down
228 changes: 228 additions & 0 deletions src/patterns/structural/Decorator.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,228 @@
// Decorator is a structural design pattern that lets you attach new behaviors to objects
// by placing these objects inside special wrapper objects that contain the behaviors.
// Appicability:
// (*) when you need to be able to assign extra behaviors to objects at runtime without breaking the code that uses these objects.
// (**) when it’s awkward or not possible to extend an object’s behavior using inheritance.
// UML: docs/uml/patterns_structural_decorator.drawio.svg

#include <iostream>
#include <string>
#include <list>
#include <algorithm>

namespace
{
namespace Problem
{

class IComponent
{
public:
virtual ~IComponent() {}
virtual std::string operation() const = 0;
};

class ConcreteComponent : public IComponent
{
public:
std::string operation() const override
{
return "ConcreteComponent";
}
};

class ComponentWithA : public ConcreteComponent
{
public:
std::string operation() const override
{
return ConcreteComponent::operation() + " + FeatureA";
}
};

class ComponentWithB : public ConcreteComponent
{
public:
std::string operation() const override
{
return ConcreteComponent::operation() + " + FeatureB";
}
};

class ComponentWithAandB : public ConcreteComponent
{
public:
std::string operation() const override
{
return ConcreteComponent::operation() + " + FeatureA + FeatureB";
}
};

// [P1]
// If you have 3 features , e.g FeatureC -> many combinations
// If you have 5 features -> 32 subclasses

namespace Client
{
void clientCode(const IComponent &comp)
{
std::cout << comp.operation() << "\n";
}
}

void run()
{
std::cout << "\n\nProblem\n";
IComponent *simple = new ConcreteComponent;
Client::clientCode(*simple);

IComponent *withA = new ComponentWithA;
Client::clientCode(*withA);

IComponent *withB = new ComponentWithB;
Client::clientCode(*withB);

IComponent *withAB = new ComponentWithAandB;
Client::clientCode(*withAB);

delete simple;
delete withA;
delete withB;
delete withAB;
}

}

namespace DecoratorPattern
{
class IComponent
{
public:
virtual ~IComponent() {}
virtual std::string operation() const = 0;
};

/**
* Concrete Component
* - is a class of objects being wrapped.
* - defines the basic behavior, which can be altered by decorators.
*/
class ConcreteComponent : public IComponent
{
public:
std::string operation() const override
{
return "ConcreteComponent";
}
};

/**
* The base Decorator class follows the same interface as the other components.
* - has a field for referencing a wrapped object.
* - the field’s type should be declared as the component interface so it can contain both concrete components and decorators.
* - the base decorator delegates all operations to the wrapped object.
*/
class BaseDecorator : public IComponent
{
protected:
IComponent *m_component;

public:
explicit BaseDecorator(IComponent *component) : m_component{component} {}

/**
* The Decorator delegates all work to the wrapped component.
*/
std::string operation() const override
{
return m_component->operation();
}
};

/**
* Concrete Decorators :
* - call the wrapped object and alter its result in some way.
* - define extra behaviors that can be added to components dynamically.
* - override methods of the base decorator and execute their behavior either before
* or after calling the parent method.
*/
class ConcreteDecoratorA : public BaseDecorator
{
public:
explicit ConcreteDecoratorA(IComponent *component) : BaseDecorator{component} {}

std::string operation() const override
{
return BaseDecorator::operation() + " + FeatureA";
}
};

class ConcreteDecoratorB : public BaseDecorator
{
public:
explicit ConcreteDecoratorB(IComponent *component) : BaseDecorator{component} {}

std::string operation() const override
{
return BaseDecorator::operation() + " + FeatureB";
}
};

class ConcreteDecoratorC : public BaseDecorator
{
public:
explicit ConcreteDecoratorC(IComponent *component) : BaseDecorator{component} {}

std::string operation() const override
{
return BaseDecorator::operation() + " + FeatureC";
}
};

namespace Client
{
void clientCode(const IComponent &comp)
{
std::cout << comp.operation() << "\n";
}
}

void run()
{
std::cout << "\n\nDecorator\n";
IComponent *simple = new ConcreteComponent;
Client::clientCode(*simple);

IComponent *withA = new ConcreteDecoratorA(simple);
Client::clientCode(*withA);

IComponent *withB = new ConcreteDecoratorB(simple);
Client::clientCode(*withB);

IComponent *withAB = new ConcreteDecoratorB(withA);
Client::clientCode(*withAB);

IComponent *withABC = new ConcreteDecoratorC(withAB);
Client::clientCode(*withABC);

delete simple;
delete withA;
delete withB;
delete withAB;
delete withABC;
}
}

}

struct DecoratorAutoRuner
{
DecoratorAutoRuner()
{
std::cout << "\n--- Decorator Pattern Example ---\n";
Problem::run();
DecoratorPattern::run();
}
};

static DecoratorAutoRuner instance;
2 changes: 1 addition & 1 deletion src/patterns/structural/Facade.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
// Appicability:
// (*) when you need to have a limited but straightforward interface to a complex subsystem.
// (**) when you want to structure a subsystem into layers.
// UML: none
// UML: docs/uml/patterns_structural_facade.drawio.svg

#include <iostream>
namespace
Expand Down