Как разработать универсальный класс, чтобы функциональность была ограничена в зависимости от производного типа?

Если у меня есть класс Cat and Dog, реализующий PetBase. И каждый из них содержит объект с именем Owner. А Владелец держит объект под названием Эмоция. Как ограничить доступ к определенным свойствам, функциям или параметрам функций в классе Emotion в зависимости от того, принадлежит ли он кошке или собаке? Вот так:

Dog d = new Dog();
d.Owner.Emotion.SetFearLevel(10); // dog owners can have a fear level from 1-10 so let the user decide.
Cat c = new Cat();
c.Owner.Emotion.SetFearLevel(); // all cat owners have the same fear level so I don't want the user to be able to pass in a parameter but still be able to call SetFearLevel(). How do I enforce this?

В этом примере я хочу запретить владельцам кошек передавать параметр в SetFearLevel(), но дать владельцам собак возможность бояться столько, сколько они хотят (т.е. иметь возможность передавать параметр в SetFearLevel()). ()).

Что мне нужно изменить в дизайне?

[ИЗМЕНИТЬ]

Это была жеребьевка между ответами Джордао и Дэвида Фрэнсиса. В конце концов, я остановился на дизайне Дэвида Фрэнсиса из-за древовидной структуры приложения.


person goku_da_master    schedule 10.07.2012    source источник
comment
Ваши теги говорят об инкапсуляции, но вы описываете питомца, у которого есть владелец, у которого есть эмоция, у которой есть страх, который зависит от типа трехсоставного класса. Что бы я изменил? Вся модель, потому что, поскольку она у вас есть, каждый класс должен знать подробности о других.   -  person msw    schedule 11.07.2012
comment
Я добавлю для вас тег наследования, но инкапсуляция везде в наследовании. Кроме того, это нормально слышать проблемы с моделью, но я искал решение. Если вы знаете лучший способ, поделитесь.   -  person goku_da_master    schedule 11.07.2012
comment
Не зная, что вы пытаетесь смоделировать, я не могу предложить замену, извините. Но я вижу, что OOD, которые могут закончиться катастрофой, действительно демонстрируют некоторые общие черты, и одно из них — размазанное знание типов. Инкапсуляция или наследование не имеет значения.   -  person msw    schedule 11.07.2012
comment
Вы должны просто генерировать исключение, если кто-то делает что-то недопустимое. Кстати: если вы расскажете нам о своей реальной проблеме, мы могли бы действительно улучшить ваш дизайн, который, вероятно, включает в себя все хорошее, что есть в ООП.   -  person user1494736    schedule 12.07.2012


Ответы (3)


SetFearLevel — это другая сигнатура, поэтому вам нужны 2 разных подтипа базового типа эмоции.
Тогда вам понадобится отдельный подтип владельца для каждого типа питомца.
Типы возвращаемых значений обычно могут быть ковариантными (т. е. подтипом), поэтому каждый владелец subtype может возвращать конкретный подтип Emotion, который применяется к этому владельцу.

person davidfrancis    schedule 10.07.2012
comment
Я склонен согласиться со всеми подтипами - не уверен, что с этим можно что-то умное сделать... - person davidfrancis; 11.07.2012

Вы можете инкапсулировать доступ к нужным вам функциям в самих классах:

dog.setOwnerFearLevel(5);
cat.setOwnerFear();

Только будьте осторожны с трансмогрификаторами Деметры.

person Jordão    schedule 11.07.2012
comment
Я никогда не слышал о трансмогрификаторах Деметры. Спасибо, что научили меня. Недавно я прочитал, что нужно следовать закону Деметры за некоторыми исключениями. Интересно, будет ли мой случай исключением (transmogrifer), потому что кошка/собака должны вызывать пару функций и использовать пару свойств в классе Owner. - person goku_da_master; 12.07.2012

Ваши связи неправильные. Вы хотите начать с owner.SetFearLevel(5). Владелец owner должен знать о своем питомце и своих эмоциях. Следовательно, метод может проверять: «Есть ли у меня кошка или собака?» а затем правильно установите экземпляр эмоции: «Я не боюсь, несмотря на этот параметр, равный 5 (потому что у меня есть кошка)». Или, другими словами, владелец ссылается на домашнее животное, а не домашнее животное на владельца.

Чтобы увидеть это более ясно, обратите внимание, что ваша модель легко позволяет одному человеку владеть любым количеством собак и кошек. Вы всегда можете создать нового питомца и сделать этого незадачливого человека владельцем. Это может быть полезно, но делает расчет его/ее уровня страха довольно сложным. В каком-то смысле это почти невозможно, потому что, хотя для любого питомца вы знаете владельца, для любого владельца вы не знаете питомца. (Легко решаемая проблема, я признаю.)

Итак, добавьте ссылку на питомца (или питомцев — возможно, используйте максимальный фактор страха) в классе Owner и переместите метод SetFearLevel в класс Owner из класса Emotion, и все должно хорошо сочетаться друг с другом.

person RalphChapin    schedule 11.07.2012
comment
Это сработало бы, если бы у меня уже был владелец. Но в этом приложении питомцы на высшем уровне. Все о домашних животных. Мне не нужно знать, какие домашние животные есть у владельца. Кто хозяин для каждого питомца. - person goku_da_master; 12.07.2012
comment
В этом случае вы заставляете свой класс Owner работать слишком усердно — на самом деле это не более чем имя. Уровень/эмоции страха являются функцией питомца и, по логике, не имеют ничего общего с владельцем. Поместите SetFearLevel в Cat and Dog (как предлагает Джордао) (через базовый класс или интерфейс), и все готово. С несколько эмоциональными терминами, подобными этим, вы должны быть осторожны, чтобы мыслить логически. Попробуйте заменить такие классы, как Car, Airplane и Passenger, и используйте SetTopSpeed ​​для своего метода. Та же логика, но немного яснее, куда все идет. - person RalphChapin; 12.07.2012
comment
Или, иначе говоря, вы недостаточно продумал характер каждого из ваших занятий. Вам нужно подумать о том, чем на самом деле является каждый экземпляр сам по себе, и как он связан с другими объектами в программе, и, что более важно, как он связан со всеми возможными будущими объектами- -остальная вселенная. Объект должен быть полной сущностью сам по себе, а не просто битом данных со значением только как часть какой-то другой структуры. - person RalphChapin; 12.07.2012
comment
Тривиальная задача на деле. :) Спасибо за полезные советы. - person goku_da_master; 12.07.2012