В настоящее время я думаю об интерфейсе для класса, который я пишу. Этот класс содержит стили для символа, например, выделен ли он жирным шрифтом, курсивом, подчеркнут и т. Д. Я уже два дня спорю сам с собой о том, следует ли использовать методы получения / установки или логические имена для методов, которые изменяют значения на эти стили. Хотя я предпочитаю логические имена, это означает написание кода, который не так эффективен и не так логичен. Позвольте привести пример.
У меня есть класс , CharacterStyles
который имеет переменные член bold
, italic
, underline
(и некоторые другие, но я оставлю их для простоты). Самый простой способ разрешить другим частям программы доступ к этим переменным - написать методы getter / setter, чтобы вы могли делать styles.setBold(true)
и styles.setItalic(false)
.
Но мне это не нравится. Не только потому, что многие люди говорят, что геттеры / сеттеры нарушают инкапсуляцию (неужели это так плохо?), Но в основном потому, что это не кажется мне логичным. Я ожидаю стилизовать персонажа одним методом styles.format("bold", true)
или чем-то подобным, но не всеми этими методами.
Хотя есть одна проблема. Поскольку вы не можете получить доступ к переменной-члену объекта по содержимому строки в C ++, я должен был бы либо написать большой контейнер if-Statement / switch для всех стилей, либо мне пришлось бы хранить стили в ассоциативном массиве ( карта).
Я не могу понять, как лучше. В один момент я думаю, что должен написать геттеры / сеттеры, а в следующий момент я склоняюсь в другую сторону. Мой вопрос: что бы вы сделали? И зачем ты это делаешь?
источник
bold
установленным вtrue
и другими неопределенными переменными, методы получения для других переменных должны возвращать значение родительского стиля (который хранится в другом свойстве), в то время как получение дляbold
свойства должно возвращатьсяtrue
. Есть и другие вещи, такие как имя и способ отображения в интерфейсе.Ответы:
Да, геттеры / сеттеры нарушают инкапсуляцию - они в основном просто дополнительный уровень между прямым доступом к базовому полю. Вы могли бы также просто получить к нему доступ напрямую.
Теперь, если вам нужны более сложные методы для доступа к полю, это допустимо, но вместо того, чтобы выставлять поле, вам нужно подумать, какие методы класс должен предлагать вместо этого. то есть. вместо класса Bank со значением Money, которое определяется с помощью свойства, вам нужно подумать, какие типы доступа должен предлагать объект Bank (добавить деньги, вывести, получить баланс) и реализовать их вместо этого. Свойство переменной Money только синтаксически отличается от прямого доступа к переменной Money.
У DrDobbs есть статья, которая говорит больше.
Для вашей проблемы у меня было бы 2 метода setStyle и clearStyle (или любой другой), которые принимают перечисление возможных стилей. Оператор switch внутри этих методов затем применяет соответствующие значения к соответствующим переменным класса. Таким образом, вы можете изменить внутреннее представление стилей на что-то другое, если позже решите сохранить их в виде строки (например, для использования в HTML) - то, что потребовало бы изменения всех пользователей вашего класса, если бы вы использовали получить / установить свойства.
Вы все еще можете включить строки, если хотите принять произвольные значения, либо иметь большой оператор if-then (если их несколько), либо сопоставить строковые значения с указателями на методы, используя std :: mem_fun (или std :: функция ), так что «полужирный» будет храниться в ключе карты с его значением, являющимся sts :: mem_fun для метода, который устанавливает переменную полужирный в true (если строки совпадают с именами переменных-членов, то вы также можете использовать stringifying макрос , чтобы уменьшить количество кода , вам нужно написать)
источник
styles.setStyle(BOLD, true)
? Это верно?styles.getStyle(BOLD)
когда у вас есть не только переменные-члены типа boolean, но также и типы integer и string (например:)styles.getStyle(FONTSIZE)
. Поскольку вы не можете перегружать типы возвращаемых данных, как вы программируете это? Я знаю, что вы можете использовать пустые указатели, но для меня это звучит очень плохо. Есть ли у вас какие-либо советы, как это сделать?Одна идея, которую вы, возможно, не рассматривали, это шаблон декоратора . Вместо того, чтобы устанавливать флаги в объекте и затем применять эти флаги ко всему, что вы пишете, вы оборачиваете класс, который пишет в Decorators, которые, в свою очередь, применяют стили.
Вызывающему коду не нужно знать, сколько из этих оболочек вы поместили в текст, вы просто вызываете метод для внешнего объекта, и он вызывает стек.
Для примера псевдокода:
И так далее, для каждого стиля украшения. В его простейшем использовании вы можете сказать
И коду, который вызывает этот метод, не нужно знать детали того, что он получает. Пока что-то может рисовать текст через метод WriteString.
источник
TextWriter
нужно поговорить с обоимиBoldDecorator
иItalicDecorator
(в двух направлениях), чтобы выполнить работу.Я бы склонялся ко второму решению. Это выглядит более элегантно и гибко. Хотя трудно представить другие типы, кроме жирного, курсива и подчеркивания (зачеркнуты?), Было бы трудно добавить новые типы с помощью переменных-членов.
Я использовал этот подход в одном из моих последних проектов. У меня есть класс, который может иметь несколько логических атрибутов. Количество и названия атрибутов могут меняться со временем. Я храню их в словаре. Если атрибут отсутствует, я предполагаю, что его значение равно «false». Я также должен хранить список доступных имен атрибутов, но это уже другая история.
источник
Я думаю, что вы продумываете проблему.
styles.setBold(true)
иstyles.setItalic(false)
все в порядкеисточник