我本质上是一组类型,它们彼此共享一些共同的属性。实际上,我可以使用C ++类继承对这种关系进行建模。但是,我还需要在代码中传递并存储这些对象,并且将每个实例都保留为多态堆引用是很痛苦的。
这是初始情况:
具有所有“子类”值的枚举类型:
enum class PhoneType {
landline,
cell
}
存储并传递给 lot 的类型:
class Phone {
public:
static Phone landline(PhoneNumber number) {
return Phone(PhoneType::landline, number);
}
static Phone cell(PhoneNumber number, optional<AppList> apps) {
return Phone(PhoneType::cell, number, apps)
}
PhoneType type() { return _type; }
PhoneNumber number() { return _number; }
private:
PhoneType _type;
PhoneNumber _number;
optional<AppList> _apps;
Phone(PhoneType type, PhoneNumber number) :
_type(type), _number(number)
{}
Phone(PhoneType type, PhoneNumber number, optional<AppList> apps) :
_type(type), _number(number), _apps(apps)
{}
};
PhoneType
枚举Phone
的不同可能类型,它们全部具有PhoneNumber
,可能具有也可能没有AppList
。
问题是一旦呼叫者确定它正在处理AppList
电话,如何使外界访问电话的cell
。请注意,我不想简单地出售可选类型,因为这会将大量错误检查代码压入调用函数,这不是我想要的(在大多数情况下,调用者知道{{ PhoneType
中的1}}甚至不需要检查就可以通过,因此售卖Phone
只是不必要的痛苦。
我可以将额外的访问器添加到optional<>
类中,并记录它们抛出/崩溃/等的情况。如果接收到的Phone
不代表Phone
电话。但是,在实际代码中,还有更多此类属性需要更多访问器,并且在调用站点读取这些访问器时,每个访问器的先决条件都不清楚。
长话短说,经过一番考虑,我最终想到了这个成语:
在cell
定义之前:
Phone
在class CheckedPhoneRef {
public:
CheckedPhoneRef() = delete;
Phone& phone() const { return * _phone; }
protected:
Phone* _phone;
CheckedPhoneRef(Phone* phone) : _phone(phone) {}
private:
friend class Phone;
};
class LandlineCheckedPhoneRef : public CheckedPhoneRef {
public:
using CheckedPhoneRef::CheckedPhoneRef;
};
class CellCheckedPhoneRef : public CheckedPhoneRef {
public:
using CheckedPhoneRef::CheckedPhoneRef;
AppList apps() const; // accesses private member of referenced Phone
};
的{{1}}部分中:
Phone
在public
的{{1}}部分中:
// (Comment above declarations in header):
// These assert that this Phone is of the correct PhoneType.
LandlineCheckedPhoneRef landline_ref() {
assert(_type == PhoneType::landline);
return LandlineCheckedPhoneRef(this);
}
CellCheckedPhoneRef cell_ref() {
assert(_type == PhoneType::cell);
return CellCheckedPhoneRef(this);
}
// (Plus const versions)
现在,很清楚在任何给定的呼叫站点都进行了哪些假设:如果我说Phone
,那么我肯定是在断言这部private
是一部friend LandlineCheckedPhoneRef;
friend CellCheckedPhoneRef;
电话,例如,
phone.cell_ref()
(愚蠢的示例,但您明白了。我知道我可以在这里使用访问模式,但实际代码并不完全是这样。)
我喜欢我正在做的设计。问题是,我不太知道如何命名自动包装器类型。我目前正在使用phone
,cell
等模式,但是我知道“ lens”在编程中已经具有其他含义。也许这不是一个大问题,但是我想问一下,确保我没有错过一个更完善的命名方案。
这个模式/习惯用法是否有一个确定的名称,其中某个类型出售包装器以扩展其接口?
答案 0 :(得分:1)
不幸的是,您的意图对我而言并不十分清楚。
起初,我认为您只是重新发明了 decorator pattern ,在其中您可以向现有对象动态添加一些职责(访问者)。
但仔细观察,我认为这一切都像是一个反模式,一个依赖混乱和一个有缺陷的设计:在基类中,您需要成为派生类的朋友上课时,您应该有响起的警钟。
您最好设计更简洁的设计,而不要寻找名称。忘记枚举,然后去一个抽象的LandLine
基类,它的抽象功能对应于每部电话应具有的功能。然后创建两个派生的具体类:CellPhone
和Phone
,它们都从LandLine
继承。
现在,您可以考虑获取应用程序列表是所有电话的常用功能,而TelepathyPhone
仅返回一个空列表。然后,您所有的代码都将仅使用build in polymorphism以适当的可扩展方式完成此工作:
TelepathyPhone::displayBrainWavelength()
,则只需实现抽象接口所需的通用功能,所有使用代码仍将保持不变。 if
),则可以使用dynamic_cast
<div>
。至少您每次创建新的派生类时都避免创建新的枚举。