У меня есть контейнер для базового класса с объектами разных типов, а мне нужно выбрать из него элементы только одного типа, небазового. Кажется, что getClassName это не совсем чистый код и должно быть более хорошее решение.
Здравствуйте, Ashley, Вы писали:
A>У меня есть контейнер для базового класса с объектами разных типов, а мне нужно выбрать из него элементы только одного типа, небазового. Кажется, что getClassName это не совсем чистый код и должно быть более хорошее решение.
например специально для таких случаев я обычно завожу enum name {CHERRY, LEMON, APPLE, COUNT}
который инициализируется автоматом в конструкторе
class Fruit { enum Name{CHERRY, LEMON, APPLE, COUNT} name;}
class Apple : Fruit (Name::APPLE){}
...
перебор
if (it->name == Fruit::Name::APPLE)
{
динамик_каст
ассерт
если не ноль то работаем дальше
}
это нарушает принцип что базовый класс не должен знать о существовании наследников, но лучше и компактней способа я не знаю
Re[2]: частный вопрос про хороший стиль
От:
Аноним
Дата:
23.12.10 09:18
Оценка:
__>перебор __>if (it->name == Fruit::Name::APPLE) __>{ __> динамик_каст __> ассерт __> если не ноль то работаем дальше __>} __>это нарушает принцип что базовый класс не должен знать о существовании наследников, но лучше и компактней способа я не знаю
И это в форуме "Архитектура программного обеспечения"?
A>У меня есть контейнер для базового класса с объектами разных типов, а мне нужно выбрать из него элементы только одного типа, небазового. Кажется, что getClassName это не совсем чистый код и должно быть более хорошее решение.
getClass в языках с поддержкой reflection в общем случае вполне нормальное решение. Проблема может быть скорее в том, зачем вам это понадобилось.
Здравствуйте, Ashley, Вы писали:
A>У меня есть контейнер для базового класса с объектами разных типов, а мне нужно выбрать из него элементы только одного типа, небазового. Кажется, что getClassName это не совсем чистый код и должно быть более хорошее решение.
Сыграйте на полиморфизме. Можно сделать виртуальный/абстрактный метод, который возвращает bool. Пусть в нужном вам подклассе этот метод всегда возвращает true, а во всех остальных — false. Тогда вы сможете перебрать коллекцию и выбрать нужные объекты по значению, которое возвращает этот метод-фильтр.
С другой стороны, если у вас 10 подклассов и нужно выбирать объекты любого из этих 10 классов, то создавать 10 виртуальных методов глупо. Возможно, лучшим вариантом будет рефлекшн. Либо паттерн Visitor, если хотите хорошей масштабируемости. Либо — пересмотреть дизайн.
Здравствуйте, Аноним, Вы писали:
__>>перебор __>>if (it->name == Fruit::Name::APPLE) __>>{ __>> динамик_каст __>> ассерт __>> если не ноль то работаем дальше __>>} __>>это нарушает принцип что базовый класс не должен знать о существовании наследников, но лучше и компактней способа я не знаю
А>И это в форуме "Архитектура программного обеспечения"?
ну раз вам так смешно, значит я какую-то глупость написал. пишу на С++ уже 10 лет, поэтому вы наверное пишете все 20. всегда приятно узнать что-то новое от настолько опытного человека. делитесь своим опытом — как сделать в С++ лучше, чем я предложил.
Здравствуйте, __kot2, Вы писали: А>>И это в форуме "Архитектура программного обеспечения"? __>ну раз вам так смешно, значит я какую-то глупость написал. пишу на С++ уже 10 лет, поэтому вы наверное пишете все 20. всегда приятно узнать что-то новое от настолько опытного человека. делитесь своим опытом — как сделать в С++ лучше, чем я предложил.
ну и давайте даже задачу уточню — есть коллекция фруктов, нужно помимо кучи всяких вещей которые можно делать с фруктами нужно уметь выбирать из коллекции все фрукты по некоему идентификатору типа
Здравствуйте, __kot2, Вы писали:
__>Здравствуйте, __kot2, Вы писали: А>>>И это в форуме "Архитектура программного обеспечения"? __>>ну раз вам так смешно, значит я какую-то глупость написал. пишу на С++ уже 10 лет, поэтому вы наверное пишете все 20. всегда приятно узнать что-то новое от настолько опытного человека. делитесь своим опытом — как сделать в С++ лучше, чем я предложил. __>ну и давайте даже задачу уточню — есть коллекция фруктов, нужно помимо кучи всяких вещей которые можно делать с фруктами нужно уметь выбирать из коллекции все фрукты по некоему идентификатору типа
Паттерн Visitor:
class Program {
static void Main(string[] args){
var fructs=new List<Fruct>();
fructs.Add(new Apple());
fructs.Add(new Apple());
fructs.Add(new Pear());
var visitor=new Visitor();
foreach(var fruct in fructs){
fruct.Access(visitor);
}
}
}
//базовый для всех фруктов или интерфейсpublic abstract class Fruct{
public abstract void Access(Visitor visitor);
}
//яблокоpublic class Apple:Fruct{
public override void Access(Visitor visitor){
visitor.Visit(this);
}
}
//грушаpublic class Pear:Fruct{
public override void Access(Visitor visitor){
visitor.Visit(this);
}
}
public class Visitor{
public void Visit(Apple apple){
//ложим в нужную колекцию
//............
}
public void Visit(Pear pear){
//ложим в нужную колекцию
//......................
}
}
Здравствуйте, Ashley, Вы писали:
A>У меня есть контейнер для базового класса с объектами разных типов, а мне нужно выбрать из него элементы только одного типа, небазового. Кажется, что getClassName это не совсем чистый код и должно быть более хорошее решение.
А зачем вам это делать? Нарушение LSP без необходимости — большой грех.
Есть одно исключение: иерархия фиксирована, те не планируется добавление наследников. такое может встретиться в AST. Тогда чисто ОО-способ это паттерн Visitor.
НО! Строго фиксированных иерархий не бывает, обычно рано или поздно требуется добавление наследников. Если такой сценарий реален, то можно заниматься type-testing_ом в рекурсивных функциях обхода, для этого можно использовать как встроенные функции получения типа, так и свои идентификаторы. Первый способ надежнее, второй быстрее.
Здравствуйте, out-of-the-way, Вы писали:
OOT>Здравствуйте, __kot2, Вы писали:
__>>Здравствуйте, __kot2, Вы писали: А>>>>И это в форуме "Архитектура программного обеспечения"? __>>>ну раз вам так смешно, значит я какую-то глупость написал. пишу на С++ уже 10 лет, поэтому вы наверное пишете все 20. всегда приятно узнать что-то новое от настолько опытного человека. делитесь своим опытом — как сделать в С++ лучше, чем я предложил. __>>ну и давайте даже задачу уточню — есть коллекция фруктов, нужно помимо кучи всяких вещей которые можно делать с фруктами нужно уметь выбирать из коллекции все фрукты по некоему идентификатору типа
OOT>Паттерн Visitor:
спасибо за то, что обьяснили как грамотно выделять обьекты нужного типа и по разному с ними что-то делать. правда приведенный вами код конечно же не выделяет обьекты одного типа по идентификатору, как я просил, а разбивает коллекцию на коллекции уже известных типов на момент написания класса, но логика понятна.
я решил прорефакторить свой старый гавенный код, уже половину прорефакторил. сущностей конечно наплодил новых целый вагон, зато все как надо. вот короче, прорефакторил я половину где-то и споткнулся о функцию, которая
принимает на вход коллекцию и три идентификатора фруктов.
фрукты первого типа из коллекции нужно удалить.
фрукты второго типа нужно добавить в другую коллекцию
над фруктами третьего типа нужно вызвать ф-ию f()
но мастер, я не могу придумать способ как бы чтобы это не громоздко и коряво было. я подумал что стоит избавляться от идентификаторов типов фруктов вообще, но это код из игры — часть типов выбирает пользователь, часть выбирается случайно, ф-ия g — это часть логики игры и я не вижу способа как избавиться от типов. подскажи, как прорефакторить g?