В приведенном вами примере ни заводской, ни шаблонный подход не имеют смысла для меня.
Мое решение включает член данных в классе Pen.
class Pen {
public:
Pen() : m_color(0,0,0,0) /* the default colour is black */
{
}
Pen(const Color& c) : m_color(c)
{
}
Pen(const Pen& other) : m_color(other.color())
{
}
virtual void Draw()
{
cout << "Drawing with a pen of color " << m_color.hex();
}
void setColor(const Color& c) { m_color = c; }
const Color& color() const { return m_color; }
private:
Color m_color;
};
class Color {
public:
Color(int r, int g, int b, int a = 0) :
m_red(r), m_green(g), m_blue(other.blue()), m_alpha(a)
{
}
Color(const Color& other) :
m_red(other.red()), m_green(other.green()),
m_blue(other.blue()), m_alpha(other.alpha())
{
}
int red() const { return m_red; }
int green() const { return m_green; }
int blue() const { return m_blue; }
int alpha() const { return m_alpha; }
std::string hex() const
{
std::ostringstream os;
char buf[3];
os << "#";
sprintf(buf, "%2X", red());
os << buf;
sprintf(buf, "%2X", green());
os << buf;
sprintf(buf, "%2X", blue());
os << buf;
sprintf(buf, "%2X", alpha());
os << buf;
return os.str();
}
private:
int m_red;
int m_green;
int m_blue;
int m_alpha;
}
Конечно, цветовой класс должен быть скорректирован в соответствии с используемым API-интерфейсом рисования, и, возможно, он будет более продвинутым, чем этот (различные цветовые пространства и т. Д.).
Почему не шаблоны?
Причина, по которой нет смысла использовать шаблоны, заключается в том, что (предположительно) единственное различие между различными операциями рисования - это переменная цвета. Таким образом, используя шаблоны (или вручную объявляя различные классы, как вы это сделали), вы дублируете похожий код. Это сделает вашу программу большой и замедлит ее.
Таким образом, функция рисования должна либо принимать цвет в качестве аргумента, либо (как в моем примере) иметь цвет в качестве члена данных класса.