Как зайти в Даркнет?!
25th January, 01:11
6
0
Как в tkinter из поля ввода Entry получить значение в одну переменную и обновить строку кнопкой, затем получить ещё одно введённое значение и затем сложить их. Ниже пример кода
21st July, 19:00
895
0
Программа, которая создает фейковые сервера в поиске игровых серверов CS 1.6 Steam
21st March, 17:43
948
0
Очень долго работает Update запрос Oracle
27th January, 09:58
914
0
не могу запустить сервер на tomcat HTTP Status 404 – Not Found
21st January, 18:02
905
0
Где можно найти фрилансера для выполнения поступающих задач, на постоянной основе?
2nd December, 09:48
938
0
Разработка мобильной кроссплатформенной военной игры
16th July, 17:57
1724
0
период по дням
25th October, 10:44
3955
0
Пишу скрипты для BAS только на запросах
16th September, 02:42
3720
0
Некорректный скрипт для закрытия блока
14th April, 18:33
4613
0
прокидывать exception в блоках try-catch JAVA
11th March, 21:11
4381
0
Помогите пожалуйста решить задачи
24th November, 23:53
6086
0
Не понимаю почему не открывается детальное описание продукта
11th November, 11:51
4351
0
Нужно решить задачу по программированию на массивы
27th October, 18:01
4396
0
Метода Крамера С++
23rd October, 11:55
4309
0
помогите решить задачу на C++
22nd October, 17:31
4002
0
Помогите решить задачу на python с codeforces
22nd October, 11:11
4492
0
Python с нуля: полное руководство для начинающих
18th June, 13:58
2599
0
Наследование и полиморфизм - простота использования против чистоты
В проекте наша команда использует списки объектов для выполнения массовых операций над наборами данных, которые должны обрабатываться аналогичным образом. В частности, различные объекты идеально действовали бы одинаково, что было бы очень легко достигнуто с помощью полиморфизма. Проблема, с которой я сталкиваюсь, заключается в том, что наследование подразумевает, что это отношение, а не имеет отношения. Например, у нескольких объектов есть счетчик повреждений, но чтобы сделать это простым в использовании в списке объектов, можно использовать полиморфизм - за исключением того, что это будет означать отношение, которое не будет истинным. (Человек не является счетчиком ущерба.)
Единственное решение, которое я могу придумать, состоит в том, чтобы член класса возвращал правильный тип объекта при неявном приведении вместо того, чтобы полагаться на наследование. Было бы лучше отказаться от is a / has a ideal в обмен на простоту программирования?
Редактировать: Чтобы быть более конкретным, я использую C++, поэтому использование полиморфизма позволит различным объектам "act the same" в том смысле, что производные классы могут находиться в одном списке и управляться виртуальной функцией базового класса. Использование интерфейса (или имитация их через наследование) кажется решением, которое я хотел бы использовать.
Я думаю, что вы должны реализовывать интерфейсы, чтобы иметь возможность применять свои отношения has a (я делаю это в C#):
public interface IDamageable
{
void AddDamage(int i);
int DamageCount {get;}
}
Вы можете реализовать это в своих объектах:
public class Person : IDamageable
public class House : IDamageable
И Вы были бы уверены, что DamageCount свойство и имеет метод, позволяющий вам добавить ущерб, не подразумевая, что человек и дом связаны друг с другом в какой-то наследственности.
Это может быть достигнуто с помощью множественного наследования. В вашем конкретном случае (C++) вы можете использовать чистые виртуальные классы в качестве интерфейсов. Это позволяет иметь множественное наследование без создания проблем области / неоднозначности. Пример:
class Damage {
virtual void addDamage(int d) = 0;
virtual int getDamage() = 0;
};
class Person : public virtual Damage {
void addDamage(int d) {
// ...
damage += d * 2;
}
int getDamage() {
return damage;
}
};
class Car : public virtual Damage {
void addDamage(int d) {
// ...
damage += d;
}
int getDamage() {
return damage;
}
};
Теперь и Человек, и автомобиль 'is-a' повреждения, то есть они реализуют интерфейс повреждения. Использование чисто виртуальных классов (чтобы они были похожи на интерфейсы) является ключевым и должно использоваться часто. Он изолирует будущие изменения от изменения всей системы. Для получения дополнительной информации ознакомьтесь с принципом "открыто-закрыто".
Я согласен с Джоном, но если у вас все еще есть потребность в отдельном классе счетчика повреждений, вы можете сделать это:
class IDamageable {
virtual DamageCounter* damage_counter() = 0;
};
class DamageCounter {
...
};
Затем каждый повреждаемый класс должен предоставить свою собственную функцию-член damage_counter(). Недостатком этого является то, что он создает vtable для каждого повреждаемого класса. Вы можете вместо этого использовать:
class Damageable {
public:
DamageCounter damage_counter() { return damage_counter_; }
private:
DamageCounter damage_counter_;
};
Но многим людям не нравится множественное наследование, когда у нескольких родителей есть переменные-члены.
Иногда стоит отказаться от идеала ради реалистичного. Если это вызовет огромную проблему для "do it right" без реальной пользы, то я сделаю это неправильно. При этом я часто думаю, что стоит потратить время, чтобы сделать это правильно, потому что ненужное множественное наследование увеличивает сложность, и это может способствовать тому, что система будет менее ремонтопригодна. Вы действительно должны решить, что лучше для ваших обстоятельств.
Один из вариантов состоял бы в том, чтобы эти объекты реализовывали интерфейс Damageable , а не наследовали от DamageCounter . Таким образом, у человека есть- счетчик повреждений, но он может быть поврежден. (Я часто нахожу, что интерфейсы имеют гораздо больше смысла как прилагательные, чем существительные.) Тогда вы могли бы иметь согласованный интерфейс повреждения на объектах Damageable , и не выставлять, что счетчик повреждений является базовой реализацией (если вам это не нужно).
Если вы хотите пройти шаблонный маршрут (предполагая C++ или аналогичный), вы можете сделать это с помощью mixins, но это может очень быстро испортиться, если сделать это плохо.
Обычно, когда мы говорим о 'is a' против 'has a', мы говорим о наследовании против композиции.
Um...damage счетчик будет просто атрибутом одного из ваших производных классов и на самом деле не будет обсуждаться в терминах "человек-счетчик ущерба" по отношению к вашему вопросу.
Видеть это:
http://www.artima.com/designtechniques/compoinh.html
Что может помочь вам на этом пути.
@ Derek : судя по формулировке, я предположил, что это был базовый клаз, перечитав вопрос, я вроде как теперь понимаю, к чему он клонит.
Этот вопрос действительно сбивает с толку :/
Ваш вопрос, выделенный жирным шрифтом, очень открыт и имеет ответ "это зависит", но ваш пример на самом деле не дает много информации о контексте, из которого вы спрашиваете. Эти строки сбивают меня с толку;
наборы данных, которые все должны быть обработаны аналогичным образом
- Каким образом? Обрабатываются ли наборы функцией? Еще один класс? Через виртуальную функцию на данных?
В частности, различные объекты идеально действовали бы одинаково, что было бы очень легко достигнуто с помощью полиморфизма
Идеал "acting the same" и полиморфизм абсолютно не связаны между собой. Как полиморфизм делает его легко достижимым?
@Kevin
Обычно, когда мы говорим о 'is a' против 'has a', мы говорим о наследовании против композиции.
Um...damage счетчик будет просто атрибутом одного из ваших производных классов и на самом деле не будет обсуждаться в терминах "человек-счетчик ущерба" по отношению к вашему вопросу.
Наличие счетчика повреждений в качестве атрибута не позволяет ему включать в коллекцию различные объекты со счетчиками повреждений. Например, человек и автомобиль могут иметь счетчики повреждений, но вы не можете иметь vector<Person|Car> или vector<with::getDamage()> или что-то подобное в большинстве языков. Если у вас есть общий базовый класс объекта, то вы можете поместить их таким образом, но тогда вы не можете получить общий доступ к методу getDamage() .
Вот в чем была суть его вопроса, когда я читал его. -Должен ли я нарушать правила № 30 и № 31 ради того, чтобы относиться к некоторым объектам так, как будто они являются одним и тем же, даже если это не так?"
"Doing it right" будет иметь преимущества в долгосрочной перспективе, хотя бы потому, что кто-то, поддерживающий систему позже, будет легче понять, правильно ли это было сделано с самого начала.
В зависимости от языка, вы вполне можете иметь возможность множественного наследования, но обычно простые интерфейсы имеют больше смысла. Под "simple" я подразумеваю создание интерфейса, который не пытается быть слишком большим. Лучше иметь много простых интерфейсов и несколько монолитных. Конечно, всегда есть компромисс, и слишком много интерфейсов, вероятно, приведут к тому, что они будут "forgotten" о...
@Andrew
Идеал "acting the same" и полиморфизм абсолютно не связаны между собой. Как полиморфизм делает его легко достижимым?
Все они имеют, например, одну общую функцию. Давайте назовем его addDamage() . Если вы хотите сделать что-то подобное:
foreach (obj in mylist)
obj.addDamage(1)
Тогда вам нужен либо динамический язык, либо они должны расширяться из общего родительского класса (или интерфейса). напр.:
class Person : DamageCounter {}
class Car : DamageCounter {}
foreach (DamageCounter d in mylist)
d.addDamage(1)
Затем вы можете лечить Person и Car одинаково в определенных очень полезных обстоятельствах.