Last active
July 25, 2022 04:51
-
-
Save ajx42/a950938c6b949df7d770e4ac0ff0131a to your computer and use it in GitHub Desktop.
Decorator Design Pattern
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <iostream> | |
#include <sstream> | |
#include <string> | |
struct Shape | |
{ | |
virtual std::string str() const = 0; | |
}; | |
struct Circle : Shape | |
{ | |
Circle() {} | |
Circle(int radius) : radius(radius) {} | |
std::string str() const override | |
{ | |
std::ostringstream oss; | |
oss << "Circle of radius " << radius; | |
return oss.str(); | |
} | |
void resize( int newRadius ) | |
{ | |
radius = newRadius; | |
} | |
private: | |
int radius = 0; | |
}; | |
struct Square : Shape | |
{ | |
Square() {} | |
Square(int side) : side(side) {} | |
std::string str() const override | |
{ | |
std::ostringstream oss; | |
oss << "Square of side " << side; | |
return oss.str(); | |
} | |
void scale( float factor ) | |
{ | |
side *= factor; | |
} | |
private: | |
int side = 0; | |
}; | |
// Dynamic Decorator | |
struct ColoredShape : Shape | |
{ | |
ColoredShape( Shape& shape, std::string color ) | |
: shape(shape), color(color) {} | |
// shape interface needs to be implemented, either differently | |
// or based on the underlying shape object. | |
std::string str() const override | |
{ | |
std::ostringstream oss; | |
oss << shape.str() << " has color " << color; | |
return oss.str(); | |
} | |
private: | |
Shape& shape; | |
std::string color; | |
}; | |
struct TransparentShape : Shape | |
{ | |
TransparentShape( Shape& shape, int transparency ) | |
: shape(shape), transparency(transparency) {} | |
std::string str() const override | |
{ | |
std::ostringstream oss; | |
oss << shape.str() << " has transparency " | |
<< (transparency / 255.f * 100.f) << " percent "; | |
return oss.str(); | |
} | |
private: | |
Shape& shape; | |
int transparency = 0; | |
}; | |
// Static Decorator | |
// template <typename T> | |
// concept IsAShape = std::is_base_of<Shape, T>::value; | |
template </*IsAShape*/ typename T> | |
struct ColoredShapeV2 : T | |
{ | |
template <typename ...Args> | |
ColoredShapeV2( std::string color, Args ...args ) | |
: color(color), T{std::forward<Args>(args)...} | |
{} | |
std::string str() const override | |
{ | |
std::ostringstream oss; | |
oss << "V2: " << T::str() << " has color " << color; | |
return oss.str(); | |
} | |
private: | |
std::string color; | |
}; | |
template </*IsAShape*/ typename T> | |
struct TransparentShapeV2 : T | |
{ | |
template <typename ...Args> | |
TransparentShapeV2( int transparency, Args ...args ) | |
: transparency(transparency), T{std::forward<Args>(args)...} | |
{} | |
std::string str() const override | |
{ | |
std::ostringstream oss; | |
oss << "V2: " << T::str() << " has transparency " | |
<< (transparency / 255.f * 100.f) << " percent"; | |
return oss.str(); | |
} | |
private: | |
int transparency = 0; | |
}; | |
int main() | |
{ | |
Circle smallCircle { 5 }; | |
std::cout << smallCircle.str() << std::endl; | |
ColoredShape smallRedCircle { smallCircle, "red" }; | |
std::cout << smallRedCircle.str() << std::endl; | |
TransparentShape smallRedInvisibleCircle { smallRedCircle, 255 }; | |
std::cout << smallRedInvisibleCircle.str() << std::endl; | |
// The issue here with dynamic decorator classes is that, methods | |
// specific to circle are not accessible via the decorated object. | |
// Eg: ERROR @ smallRedCircle.resize( 10 ) | |
ColoredShapeV2<Circle> redCircle { "red", 10 }; | |
std::cout << redCircle.str() << std::endl; | |
redCircle.resize( 15 ); | |
std::cout << redCircle.str() << std::endl; | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment