Здравствуй,
У меня есть класс под названием "Диспетчер", который управляет (создает, удаляет, изменяет и т.д.) Несколько экземпляров класса Element. Класс Element - очень простой класс (только контейнер данных).
class Manager
{
public:
void add_element(ElemKey key);
const Element *get_element(ElemKey key);
private:
container<Element> my_elements;
};
Как вы можете видеть, у меня есть метод, который возвращает Элемент пользователю. Я бы хотел, чтобы пользователь не мог ничего менять в элементе, так как это задание менеджера.
Кроме того, я хотел бы добавить метод к менеджеру, который получает указатель Element и другие параметры и изменяет Element.
Я мог бы получить ключ от элемента вместо получения указателя, но по соображениям производительности я бы хотел избежать дополнительного поиска. Что-то вроде этого:
void something_happend_to_elem_do_something(Element *elem, ...);
Проблема заключается в том, что пользователь получил указатель const, а не указатель, поэтому мне или ему нужно const_cast его. Если я это сделаю, пользователь может не понимать, что происходит, потому что даже если он дал const *, метод изменил объект. Кроме того, это, по-видимому, плохой подход.
Я подумал о других методах решения этого вопроса: 1. Элемент можно изменить на:
class Element {
public:
int get_a();
private:
int a;
};
И класс менеджера может быть другом Элемента, так что только он может его изменить. Теперь я могу удалить константу из диспетчера :: get_element
Элемент может быть изменен на:
class Element {public: virtual ~ Element() {} virtual int get_a() = 0; };
Внутри файла cpp manager будет создан еще один класс под названием ElementImpl, который только он знает с данными в нем, поэтому только он может его изменить. Как и раньше, я могу удалить константу из диспетчера :: get_element
Есть недостатки для каждого метода. Ни один из них не кажется идеальным дизайном. Я думаю, что использование только ключей в качестве параметров вместо указателей было бы лучшим подходом, но, к сожалению, я не могу сэкономить дополнительные микросекунды.
Что вы, ребята, думаете?
Наличие класса Менеджера может быть сомнительным. Следовательно, имея диспетчера, разрешающего только подмножество возможных модификаций управляемых элементов, вы можете вернуть прокси:
class Proxy {
public:
Proxy(Element& e) : e(e) {}
void modification() { e.modification(); }
private:
Proxy(const Proxy&);
Proxy& operator = (const Proxy&);
Element& e;
};