2010-11-19 3 views
1

У меня нет проблем с кодом с моей последней проблемы с ковариацией интерфейса. Сегодня я сделал еще один подход к архитектуре OLGAtherer, и я нашел огромное (для меня) препятствие. Я надеюсь, что его огромный только для меня, и я найду ответ здесь :) ОК, пожалуйста, проверьте это:Как указать на общий абстрактный класс?

У меня есть абстрактный универсальный класс:

abstract class Repository<T> where T : Entity 

этот класс содержит подписи четырех методов CRUD (добавить , вставка и т. д.) и два защищенных поля. Любой репозиторий, который я создам, должен наследовать от этого суперкласса. У меня есть хранилища, как, например:

class BookRepository : Repository<Book> 

Теперь у меня есть класс DB, который отвечает за операции на файл базы данных. И есть моя проблема. Посмотрите на этот метод, помещенного в классе DB:

void Add(List<Entity> enitites, Type entityType) 
    { 
     Repository<entityType> repo = EntitiesFactory(entityType); 
     repo.Add(entities); 
    } 

Я знаю, что выше метод не будет работать, но это визуализировать мою проблему (надеюсь) - Я хотел бы динамически создать хранилище указанного типа, но у меня есть не знаю, как это сделать. Это всегда была моя главная проблема ООП - я мог наследовать код (или реализацию интерфейсов), но я не мог использовать эти унаследованные классы. Прошу пояснить это мне. Заранее спасибо.

Paweł


Я использовал подсказки, которые вы предоставили, и это то, что я сейчас:

public void Add<T>(List<T> entities, string repoName) where T : Entity 
{ 
    Repository<T> repo = RepoFactory<T>(repoName, typeof(T)); 
    repo.Add(entities); 
} 

private Repository<T> RepoFactory<T>(string repoName, Type t) where T : Entity 
{ 
    if (t == typeof(Book)) 
    { 
    Repository<T> repo = (Repository<T>)((object)(new BookRepository(this.ConnectionString, repoName))); 
    } 

    return null; 

}

RepoFactory теперь в классе DB (который, к путь, какой-то мост здесь) - он должен быть перемещен в другом месте, вероятно, но это не главная проблема.

Во-первых, я не знаю, реализуется ли тело RepoFactory надлежащим образом - я думаю, нет.

Во-вторых - я предполагаю, что я вызову методы БД из другого класса (скажем, WindowsForm, для простоты). Я буду называть Add с параметром T в зависимости от выбора пользователя. Это ситуация, когда у меня проблема и исправление временно, потому что теперь DB в порядке, но если мне придется реализовать код WindowsForm, я буду сталкиваться с ней в другой раз (я думаю) - в будущем я попытаюсь выяснить ответ на тот же вопрос, но на более высоком уровне (выше БД) - надеюсь, вы меня понимаете ... Я в основном имею в виду, что я не буду знать, как динамически вызывать метод Add, потому что T будет зависеть от выбора пользователя (OLGAtherer имеет быть менеджером репозитория, который будет поддерживать книги и другие коллекции). И если пользователь попытается работать со своей книжной коллекцией, мне придется вызвать метод Add(). Если с коллекцией Comics, Add(). Я не хочу писать класс выше для каждого типа коллекции, но вместо этого используйте один вызов Add для этого.

Если вы понимаете, что я имею в виду, вы действительно хороши :) Мой английский отстой, но я над этим работаю. Благодарим вас за предыдущие ответы и заранее заблаговременно за помощь. Paweł

+1

Хммм, я думаю, вы пытаетесь изобрести колесо. Почему бы вам написать свой собственный ORM, если уже есть много хорошо разработанных альтернатив, таких как NHibernate и Linq2Sql? – Juliet

+0

'DB' звучит как объект God, а' EntitiesFactory' звучит как локатор сервисов. Вы настраиваете себя на незаметную, непроверенную катастрофу. – jason

+0

Здравствуйте, я знаю, что это может показаться не очень хорошей идеей - я все еще участвую, и я знаю, что освоение ООП займет много лет. Но если вы посмотрите на мой код, размещенный на Sourceforge, я думаю, что вы согласились бы с уже созданной архитектурой. Спасибо за ответ в любом случае. – skrzeczowas

ответ

7

Я не совсем уверен, чего вы хотите. Будет ли это делать?

void Add<T>(List<T> entities) where T : Entity 
{ 
    Repository<T> repo = EntitiesFactory(typeof(T)); 
    repo.Add(entities); 
} 

Кроме того, я предлагаю вам быть максимально гибким с входными параметрами, например. используйте IEnumerable<T> вместо List<T> для этого метода, а также в методе Repository<T>.Add(). Возможно, вы захотите передать лениво оцениваемый запрос или объединить несколько методов LINQ вместе.

+0

+1 Именно то, что я собирался ответить. – Sorax

+0

WOW. В любое время, когда я не знаю, что делать, и я не могу найти ответ нигде, я знаю, что могу опубликовать здесь, и я обязательно получу ответ! Благодарим вас за это и за эти полезные советы о потере зависимостей. Я хотел бы попросить вас прочитать мое новое сообщение ниже - есть следующая часть этого вопроса :) С наилучшими пожеланиями, Paweł – skrzeczowas

3

Вы можете сделать общий способ Add.

void Add<T>(List<T> enitites) 
{ 
    Repository<T> repo = EntitiesFactory(typeof(T)); 
    repo.Add(entities); 
} 
+0

Да, это он :) – skrzeczowas

2

Вы можете сделать его типобезопасным путем изменения объекта hiearchy с еще одним слоем косвенностью следующим образом:

public abstract class EntityCollection<T> : List<T> 
    where T : Entity 
{ 
    public abstract Repository<T> GetRepository(); 
} 

public class BookCollection : EntityCollection<Book> 
{ 
    public override Repository<Book> GetRepository() 
    { 
     return BookRepository(); 
    } 
} 

Итак, теперь вы можете изменить свой класс DB следующим образом:

public void Add<T>(EntityCollection<T> entities) 
{ 
    Repository<T> repo = entities.GetRepository(); 
    repo.Add(entities); 
} 

Итак, теперь вы можете передать экземпляр BookCollection в свой метод Add, и он будет работать в 100% безопасном виде, прозрачным образом.

+0

Я не знаю, является ли это именно тот ответ, который вы ищете, но его лучше сохранить он безопасен, чем сильно полагаться на листы и типовые испытания. Если вам нужно включить общий тип param, вы делаете что-то неправильно. – Juliet

+0

Джульетта, вы говорите, конечно, правильно, но на самом деле я задал вопрос выше, потому что я не знаю, как не переключиться. Было бы неплохо, если бы вы сказали мне, что не использовать переключатель. – skrzeczowas

2

Чтобы добавить ответы на все остальные, вы можете также взглянуть на шаблон дизайна инверсии управления (IoC). Это может упростить вашу жизнь в будущей работе.

С помощью инъекции зависимостей, которую дает IoC, вы можете значительно упростить использование EntitiesFactory, например.

В настоящее время я использую StructureMap, чтобы реализовать IoC, и он работает хорошо для меня.

Это страница Martin Fowler's на IoC и Wikipedia's, чтобы вы начали.

+0

Спасибо за этот ответ! Я очень рад, что у меня так много полезной информации. – skrzeczowas

1

Что бы вы ни возвращали в EntitiesFactory(), это то, что вам нужно использовать. Таким образом, проблема действительно в том, что код не был показан. Покажите код для EntitiesFactory(), и мы получим лучшее представление о том, чего вы пытаетесь выполнить.

ПРИМЕЧАНИЕ. Вы понимаете, что вы не можете перегружать типы возврата (к сожалению).

+0

К сожалению, код, который я написал в методе Add выше, является своего рода «псевдокодом». Я имею в виду, что так я хотел бы работать :) Пожалуйста, прочитайте сообщение ниже.Спасибо за ответ в любом случае. – skrzeczowas

Смежные вопросы