Algebraic Hierarchy
代数层级
Intent
To hide multiple closely related algebraic abstractions (numbers) behind a single generic abstraction and provide a generic interface to it.
将多种相关的代数抽象隐藏到一个单一的通用的抽象后面并且给它提供一个通用的接口
Motivation
In pure object-oriented languages like Smalltalk, variables are run-time bindings to objects that act like labels. Binding a variable to an object is like sticking a label on it. Assignment in these languages is analogous to peeling a label off one object and putting it on another. On the other hand, in C and C++, variables are synonyms for addresses or offsets instead of being labels for objects. Assignment does not mean re-labelling, it means overwriting old contents with new one. Algebraic Hierarchy idiom uses delegated polymorphism to simulate weak variable to object binding in C++. Algebraic Hierarchy uses Envelope Letter idiom in its implementation. The motivation behind this idiom is to be able write code like the one below.
在纯面向对象语言中像Smalltalk,变量是运行时绑定到对象,表现的像标签。绑定一个变量到一个对象就像把一个标签贴在它上面。在这些语言中赋值是类似于从一个对象剥离标签并且贴上另一个标签。另一方面在C/C++中,变量是跟地址或者偏移的同义词替代对象的标签。赋值不是意味着重新贴标签。它意味着用新的内容重写老的内容。Algebraic Hierarchy idiom使用委托的多态来模拟弱变量和对象绑定。代数层级使用Envelope Letter idiom在它的实现中。这个习语的目的是可以像下面一样写代码。
Number n1 = Complex (1, 2); // Label n1 for a complex number
Number n2 = Real (10); // Label n2 for a real number
Number n3 = n1 + n2; // Result of addition is labelled n3
Number n2 = n3; // Re-labelling
Solution and Sample Code
Complete code showing implementation of Algebraic Hierarchy idiom is shown below.
下面展示完整的Algebraic Hierarchy的实现代码
#include <iostream>
using namespace std;
struct BaseConstructor { BaseConstructor(int=0) {} };
class RealNumber;
class Complex;
class Number;
class Number
{
friend class RealNumber;
friend class Complex;
public:
Number ();
Number & operator = (const Number &n);
Number (const Number &n);
virtual ~Number();
virtual Number operator + (Number const &n) const;
void swap (Number &n) throw ();
static Number makeReal (double r);
static Number makeComplex (double rpart, double ipart);
protected:
Number (BaseConstructor);
private:
void redefine (Number *n);
virtual Number complexAdd (Number const &n) const;
virtual Number realAdd (Number const &n) const;
Number *rep;
short referenceCount;
};
class Complex : public Number
{
friend class RealNumber;
friend class Number;
Complex (double d, double e);
Complex (const Complex &c);
virtual ~Complex ();
virtual Number operator + (Number const &n) const;
virtual Number realAdd (Number const &n) const;
virtual Number complexAdd (Number const &n) const;
double rpart, ipart;
};
class RealNumber : public Number
{
friend class Complex;
friend class Number;
RealNumber (double r);
RealNumber (const RealNumber &r);
virtual ~RealNumber ();
virtual Number operator + (Number const &n) const;
virtual Number realAdd (Number const &n) const;
virtual Number complexAdd (Number const &n) const;
double val;
};
/// Used only by the letters.
Number::Number (BaseConstructor)
: rep (0),
referenceCount (1)
{}
/// Used by user and static factory functions.
Number::Number ()
: rep (0),
referenceCount (0)
{}
/// Used by user and static factory functions.
Number::Number (const Number &n)
: rep (n.rep),
referenceCount (0)
{
cout << "Constructing a Number using Number::Number\n";
if (n.rep)
n.rep->referenceCount++;
}
Number Number::makeReal (double r)
{
Number n;
n.redefine (new RealNumber (r));
return n;
}
Number Number::makeComplex (double rpart, double ipart)
{
Number n;
n.redefine (new Complex (rpart, ipart));
return n;
}
Number::~Number()
{
if (rep && --rep->referenceCount == 0)
delete rep;
}
Number & Number::operator = (const Number &n)
{
cout << "Assigning a Number using Number::operator=\n";
Number temp (n);
this->swap (temp);
return *this;
}
void Number::swap (Number &n) throw ()
{
std::swap (this->rep, n.rep);
}
Number Number::operator + (Number const &n) const
{
return rep->operator + (n);
}
Number Number::complexAdd (Number const &n) const
{
return rep->complexAdd (n);
}
Number Number::realAdd (Number const &n) const
{
return rep->realAdd (n);
}
void Number::redefine (Number *n)
{
if (rep && --rep->referenceCount == 0)
delete rep;
rep = n;
}
Complex::Complex (double d, double e)
: Number (BaseConstructor()),
rpart (d),
ipart (e)
{
cout << "Constructing a Complex\n";
}
Complex::Complex (const Complex &c)
: Number (BaseConstructor()),
rpart (c.rpart),
ipart (c.ipart)
{
cout << "Constructing a Complex using Complex::Complex\n";
}
Complex::~Complex()
{
cout << "Inside Complex::~Complex()\n";
}
Number Complex::operator + (Number const &n) const
{
return n.complexAdd (*this);
}
Number Complex::realAdd (Number const &n) const
{
cout << "Complex::realAdd\n";
RealNumber const *rn = dynamic_cast <RealNumber const *> (&n);
return Number::makeComplex (this->rpart + rn->val,
this->ipart);
}
Number Complex::complexAdd (Number const &n) const
{
cout << "Complex::complexAdd\n";
Complex const *cn = dynamic_cast <Complex const *> (&n);
return Number::makeComplex (this->rpart + cn->rpart,
this->ipart + cn->ipart);
}
RealNumber::RealNumber (double r)
: Number (BaseConstructor()),
val (r)
{
cout << "Constructing a RealNumber\n";
}
RealNumber::RealNumber (const RealNumber &r)
: Number (BaseConstructor()),
val (r.val)
{
cout << "Constructing a RealNumber using RealNumber::RealNumber\n";
}
RealNumber::~RealNumber()
{
cout << "Inside RealNumber::~RealNumber()\n";
}
Number RealNumber::operator + (Number const &n) const
{
return n.realAdd (*this);
}
Number RealNumber::realAdd (Number const &n) const
{
cout << "RealNumber::realAdd\n";
RealNumber const *rn = dynamic_cast <RealNumber const *> (&n);
return Number::makeReal (this->val + rn->val);
}
Number RealNumber::complexAdd (Number const &n) const
{
cout << "RealNumber::complexAdd\n";
Complex const *cn = dynamic_cast <Complex const *> (&n);
return Number::makeComplex (this->val + cn->rpart, cn->ipart);
}
namespace std
{
template <>
void swap (Number & n1, Number & n2)
{
n1.swap (n2);
}
}
int main (void)
{
Number n1 = Number::makeComplex (1, 2);
Number n2 = Number::makeReal (10);
Number n3 = n1 + n2;
cout << "Finished\n";
return 0;
}
参考资料
关于弱变量和强变量http://book.51cto.com/art/201012/239818.htm
参考书籍:Advanced C++ Programming Styles and Idioms
信封/信件和委托多态性