Страницы

Поиск по вопросам

понедельник, 22 октября 2018 г.

Передача параметров в класс

Необходимо создать класс. Он будет унаследован от одного из стандартных классов достаточно популярной библиотеки (не важно - предком может быть QObject Qt или CObject из MFC). При этом возникает проблема, что в класс нужно передать определенное количество параметров. Их можно передать тремя способами: в конструкторе. с помощью некой дополнительной сущности в виде метода init() с нужным количеством параметров. сделать нужное количество сеттеров и внутренних переменных класса, которые будут устанавливаться в процессе работы. У каждого способа есть плюсы и минусы. У конструктора есть серьезный плюс, что объект сразу получается готовый. У него нет промежуточных состояний. С методом init() получается, что его нужно не забыть вызвать с правильными аргументами один раз при создании объекта. Дальнейшие вызовы нежелательны (можно, например, устроить себе утечки памяти). С другой стороны, между вызовом конструктора и ф-цией init() объект получается в каком-то непонятном промежуточном состоянии, когда его полноценное использование невозможно. В третьем случае из-за обилия ф-ций запросто можно запутаться и что-то забыть. При этом у всех внутренних переменных класса, получается, должны быть какие-то значения "по умолчанию", иначе без вызова этих сеттеров экземпляр класс будет неработоспособен. С конструкторами минус мне кажется в том, что если существует достаточно большое кол-во опциональных входных параметров, то получается жесткая путаница в голове у компилятора и он просто не сможет собрать код. В конце-концов можно все параметры попытаться запаковать в структуру и передавать в конструктор указатель на нее. Но как-то это не лаконично. Например, MyObject::MyObject(int a, int b, int c); // GOOD. никаких параметров по умолчанию MyObject::MyObject(int a = 1, int b = 2; int c = 4); // GOOD MyObject::MyObject(QObject *parent = 0, int b = 2, int c = 4); //а оно вообще соберется? и не будет ли конфликта с предыдущим вариантом?
typedef struct {int *first; QObject **parent; int *b; int *c;} arguments; QObject *parent = 0; int b = 2; int c = 4; arguments ar = {NULL, &parent, &b, &c}; // NULL - как бы аргумента "нет" MyObject::MyObject(arguments &data); // нифига неизящно Короче, прошу совета - как лучше делать. Понятно, что универсальных случаев нет, но какие-то рекомендации должны существовать.


Ответ

По поводу трех способов. 2 (с методом init) - это грустно. Инициализация должна быть внутри конструктора. Хотя, некоторые "метры", изобретая Tizen (новую ОС для телефонов), выдают перлы. Доставляет и вызов метода RemoveAll в конце - как бы uninit:) третий способ это размазанный init. По факту (если set'еры имеют хоть какую то логику), приведет к трудностям инициализации - объект может находиться в состоянии кота одного известного ученого(комикс в тему). С конструкторами минус мне кажется в том, что если существует достаточно большое кол-во опциональных входных параметров, то получается жесткая путаница в голове у компилятора и он просто не сможет собрать код. Думаю, у программиста скорее наступит путаница:) а компилятор либо скомпилирует, либо нет. Как бы я делал. У таких сложных классов сделал бы приватные конструкторы (что бы их кто не попади не конструировал). Отдельно сделал бы фабрику, которая по запросу отдавала сконструированный объект (такая себе сборка паттернов фабрика и строитель). Если какой то объект может существовать в десяти разных вариантах, то значит нужно десять разных функций. При этом эти функции могут иметь один-два параметра, так и принимать другой класс/структру в качестве параметра. Так как имена будут разными, то и компилятор не запутается, и человек. (подсмотреть пример ). Второй вариант - это сделать класс, у которого конструктор будет принимать десятки параметров (но мне смутно вериться, что такой класс реально нужен, об этом ниже). И этот конструктор должен быть protected. На каждый специфический случай заводится отдельный наследник с минимумом параметров в конструкторе. Если в какой то момент кажется, что нужно добавить ещё over9000 параметров, нужно подумать, может нужно 2-3 различных класса наследника? Пример из реальной жизни - в windows много оконных элементов - окна. и представьте, если бы у Вас был только один класс окно, который делал все разновидности - окно, кнопку, поле редактирования. Третий способ. То, что нужно так много параметров, подсказывает, что похоже проектируется "божественный класс". Поэтому и вылазят такие сложности. Может с этого класса можно выделить часть данных+кода в отдельный класс/классы? А там и архитектура упростится.

Комментариев нет:

Отправить комментарий