Skip to content

Instantly share code, notes, and snippets.

@ajx42
Last active July 25, 2022 04:51
Show Gist options
  • Save ajx42/a950938c6b949df7d770e4ac0ff0131a to your computer and use it in GitHub Desktop.
Save ajx42/a950938c6b949df7d770e4ac0ff0131a to your computer and use it in GitHub Desktop.
Decorator Design Pattern
#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