У меня есть то, что по сути является семейством типов, которые имеют несколько общих свойств друг с другом.Я мог бы довольно прилично смоделировать эти отношения с наследованием классов 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
s, которые имеют PhoneNumber
и могут иметь или не иметь AppList
.
Проблема заключается в том, как обеспечить доступ к внешнему миру к номеру AppList
телефона, если вызывающий абонент уверен, чтоон имеет дело с cell
телефоном.Обратите внимание, что я не хочу просто продавать необязательный тип, так как это приводит к большому количеству кода проверки ошибок в вызывающей функции (функциях), а это не то, что мне нужно (в большинстве случаев вызывающая сторона знает * 1021).* из 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
};
В Phone
public
секции:
// (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
телефоном, например,
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() ...
}
(тупой пример, но вы понимаете, в чем дело. Я знаю, что я мог бы использовать здесь схему посещения, но настоящий код неЭто очень нравится.)
Мне нравится этот дизайн для того, что я делаю.Проблема в том, что я не знаю, как назвать вендинговые типы оберток.В настоящее время я использую шаблон LandlinePhoneLens
, CellPhoneLens
и т. Д., Но я знаю, что «объектив» уже имеет другое значение в программировании.Возможно, это не является большой проблемой, но я хотел спросить, чтобы убедиться, что я не пропустил более устоявшуюся схему именования.
Есть ли установленное имя для этого шаблона / идиомы, в котором тип торгуетоболочка, которая расширяет его интерфейс?