gpt4 book ai didi

c++ - 这个 C++ 习语是否有一个名称,其中类型出售扩展其接口(interface)的包装器?

转载 作者:行者123 更新时间:2023-11-30 04:52:24 25 4
gpt4 key购买 nike

我有一个本质上是相互共享一些共同属性的类型族。我实际上可以用 C++ 类继承相当体面地模拟这种关系。但是,我还需要在我的代码周围传递和存储这些对象,并且将每个实例都保留为多态堆引用是一件很痛苦的事情。

这是初始情况:

具有所有“子类”值的枚举类型:

enum class PhoneType {
landline,
cell
}

大量 存储和传递的类型:

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。请注意,我不想简单地提供可选类型,因为这会将大量错误检查代码推送到调用函数中,这不是我想要的(在大多数情况下,调用者知道 PhoneTypePhone 甚至无需检查就通过了,因此出售 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
};

Phonepublic 部分:

// (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)

Phoneprivate 部分:

friend LandlineCheckedPhoneRef;
friend CellCheckedPhoneRef;

现在很清楚在任何给定的调用站点做出什么假设:如果我说 phone.cell_ref() 那么我清楚地断言这个 phone 是一个 cell 电话,例如,

void call(Phone& phone) {
if (phone.type() == PhoneType::cell) {
if (has_facetime(phone.cell_ref())) ...
} else {
...
}
}

bool has_facetime(CellCheckedPhoneRef cell_phone) {
return cell_phone.apps() ...
}

(愚蠢的例子,但你明白了。我知道我可以在这里使用访问模式,但真正的代码并不完全像这样。)

我喜欢这个设计,因为我正在做的事情。问题是,我不太清楚如何命名出售的包装器类型。我目前正在使用 LandlinePhoneLensCellPhoneLens 等模式,但我知道“镜头”在编程中已经具有其他含义。也许这不是什么大问题,但我想问一下以确保我没有错过更成熟的命名方案。

是否有这种模式/习语的既定名称,其中类型出售扩展其接口(interface)的包装器?

最佳答案

很遗憾,我并不完全清楚您的意图。

起初,我以为你只是重新发明了 decorator pattern ,您可以在其中向现有对象动态添加一些职责(访问者)。

但仔细观察,我认为这一切看起来都像是一个反模式、一团困惑的依赖和一个有缺陷的设计:每次在基类中你都需要成为派生类的友元类,你应该有警钟开始响起。

与其寻找名称,不如设计一个更简洁的设计。忘掉枚举,寻找一个抽象的 Phone 基类,其抽象函数对应于每个电话应该能够做什么。然后创建两个派生的具体类:LandLineCellPhone,它们都继承自Phone

现在您可以考虑获取应用程序列表是所有类型手机的通用功能,LandLine 只会返回一个空列表。然后,您所有的代码都将只使用内置多态性以适当的可扩展方式完成工作:

  • 如果明天有人发明TelepathyPhone,您只需要实现抽象接口(interface)所需的常用功能,所有使用代码仍然可以正常工作。
  • 在最坏的情况下,如果您真的需要调用一个在通用接口(interface)中完全未知的非常具体的类相关函数(例如 TelepathyPhone::displayBrainWavelength()),您可以对于使用 dynamic_castif。至少你会避免在每次发明一个新的派生类时都创建一个新的枚举。

关于c++ - 这个 C++ 习语是否有一个名称,其中类型出售扩展其接口(interface)的包装器?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54410767/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com