2012-08-18 1 views
2

Я использую шаблон посетителя для определения набора операций над некоторыми классами.
Некоторые операции являются коммутативными, поэтому я получаю дублирование в шаблоне шаблона посетителя.
Предположим, что у меня есть классы A B C и операции: A * A, A * B, A * C, B * A, B * B, B * C, C * A, C * B, C * C.
A * A, B * B, C * C уникальны.
A * B, B * A и друзья будут иметь дублирование кода Я мог бы реализовать A * B и сделать B * A A * B, но я в конечном итоге спрошу себя: в каком файле я реализовал операцию между A и B снова, в A или в B? (будет около 6 классов, поэтому я задам этот вопрос много. 15 пар возможных операций)
Существует риск того, что кто-то в будущем сделает бесконечный цикл A * B, вызывающий B * A, вызывающий A * B при реализации новой операции.
Неестественно иметь соглашение, которое решает, какие из них должны быть реализованы A * B или B * A.
Я мог бы сделать 3-й файл со всеми реализованными функциями, которые вызывают либо A * B, и B * A, не выглядит очень объектно-ориентированным.
Как бы вы решили эту проблему?
Благодаря
(я мог бы перечислить некоторый код, но это долго и не иллюстрирует точку легко)симметричный шаблон посетителя

ответ

4

Вы правы, вы определенно должны воздерживаться от осуществления A*B как вызов B*A. В дополнение к потенциалу создания бесконечной цепочки вызовов этот подход не отражает симметрию операции в вашем коде, потому что код не симметричен.

Лучшим подходом является реализация «симметричной» операции в вспомогательном классе или в качестве функции верхнего уровня, в зависимости от того, что поддерживается на вашем языке, а затем сделать так, чтобы и вспомогательная реализация выполняла как A*B, так и B*A.

+0

есть правило, что класс не подходит для использования атрибутами других классов. Я думаю, что выбора не так много. – titus

+0

Скотт Мейер отлично обсуждает эту тему в своей более эффективной книге на C++ (пункт 31: «Выполнение функций виртуально по отношению к нескольким объектам»). Его пример - создание функции столкновения для игра, в которой различные объекты могут сталкиваться в пространстве. Его пример тоже симметричен (неважно, попадает ли астероид на космический корабль или космический корабль попадает на астероид, взрыв такой же). Он начинает с шаблона посетителя и постепенно разрабатывает C++-специфическое решение, основанное на RTTI. – dasblinkenlight

+0

это в издании 1996 года? – titus

1

Мое предложение было бы использовать конструктор, который будет выступать в качестве параметра Builder

new ParameterBuilder() 
    .setFirst("A") 
    .setSecond("B") 
    .setThird("C") 
    ... 
    .build(); 

Тогда вы будете иметь только один метод, который принимает в качестве аргумента ParameterBuilder.

+0

hmm, я мог бы реализовать материал как «Object * result = new MultiplyHelper(). AddOperand (« A »). AddOperand (« B »). Compute();' – titus

+0

У меня также есть некоторые некоммутативные функции, такие как A/B , используя симметричную конструкцию, как указано выше для несимметричной операции, не является нормально. Лучше наоборот. – titus

+0

Конструктор параметров - это просто для того, чтобы принимать параметры, что вы делаете с ними, зависит от вас. То, что вы делаете, тоже хорошо. Я предложил это решение, чтобы сохранить ваши методы неповрежденными и только изменить подпись метода. –