Как я могу разработать это лучше? (Избегание оператора switch с объектно-ориентированным дизайном) - PullRequest
8 голосов
/ 25 апреля 2011

Я немного знаю о объектно-ориентированном дизайне , но я не уверен, как использовать эти принципы в моем коде. Вот над чем я работаю:

    public void Query(Agency agency, Citation queryCitation) {
        queryCitation.AgencyCode = agency.AgencyCode;

        switch (agency.ClientDb.Type) {
            case "SQL":
                QueryOracle(agency, queryCitation);
                break;
            case "PIC":
                QueryPick(agency, queryCitation);
                break;
        }
    }

(Большинство из них являются объектами из NHibernate. Я работаю с унаследованной системой баз данных и реорганизую ее части в библиотеку кода.) Очевидно, я мог бы сделать что-то другое здесь, чтобы мне не нужны дублирующиеся функции для разных запросов к базе данных, которые имеют одинаковый ввод. Он должен просто знать, основываясь на объекте агентства, использовать ли базу данных Oracle или соединение с базой данных Pick. (Если вы никогда не слышали о базе данных Pick, у меня тоже не было, пока я не начал работать здесь. Мы делаем запросы к ней через HTTP-запросы, поэтому это не SQL.)

Должен ли я создать интерфейс, например, под названием «ClientDbConnection», а затем создать два класса, которые реализуют этот интерфейс, переместить код для запроса к базе данных и затем заменить что-то вроде «agency.clientDb.Query (queryCitation)» вся эта функция? Я думаю, что я думаю здесь вслух, но любой вклад по этому вопросу был бы оценен.

Ответы [ 6 ]

12 голосов
/ 25 апреля 2011

Агентство - это класс, которым вы управляете? Если это так, сделайте что-то вроде этого:

public abstract class GenericDb
{
    public abstract void Query(parms);
}

В вашем агентском классе вы можете иметь

public GenericDb ClientDb {get; set;}

Тогда имейте класс SqlDb как:

public class SqlDb : GenericDb
{
    public void Query(parms);
}

public class PicDb : GenericDb
{
    public void Query(parms);
}

Тогда этот код:

public void Query(Agency agency, Citation queryCitation) {
        queryCitation.AgencyCode = agency.AgencyCode;

        switch (agency.ClientDb.Type) {
            case "SQL":
                QueryOracle(agency, queryCitation);
                break;
            case "PIC":
                QueryPick(agency, queryCitation);
                break;
        }
    }

становится

public void Query(Agency agency, Citation queryCitation) {
        queryCitation.AgencyCode = agency.AgencyCode;
        agency.ClientDb.Query(queryCitation);
    }

Из-за наследования будет известно, что ClientDb имеет базовый класс GenericDb. По типу параметра ClientDb он будет знать, должен ли он запускать SqlDb, PicDb, Oracle и т. Д.

5 голосов
/ 25 апреля 2011

Скорее всего, вы захотите внедрить шаблон стратегии здесь. По сути, каждый из ваших возможных «типов» в вашем выражении switch станет собственным классом, реализующим тот же интерфейс.

Применение шаблона стратегии

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

3 голосов
/ 25 апреля 2011

Я бы использовал рефакторинг, чтобы воспользоваться интерфейсом.Я бы, вероятно, сделал что-то вроде:

public interface IQuery
{
    void Execute(Agency agency, Citation query);
}

public class OracleQuery : IQuery
{
    // Implementation
}

public class PickQuery : IQuery
{
    // Implementation
}

Затем вы могли бы изменить класс Agency, чтобы хранить экземпляр объекта IQuery вместо (или в дополнение к) объекта ClientDb:

public class Agency
{
    public IQuery Query { get; set; }
}

И затем в вашем коде инициализации (где вы обычно устанавливаете свойство ClientDb), вы можете установить экземпляр для соответствующей реализации IQuery:

agency.Query = new PickQuery();
2 голосов
/ 25 апреля 2011

Для написания меньшего количества кода, но для улучшения читаемости на уровне заявленного кода, вы можете перейти к словарю с делегатами для каждой базы данных.Это может быть легко расширено и очень легко читаемо.С этим более функциональным подходом вы получите что-то вроде

void Query(Agency agency, Citation queryCitation)
{
    Dictionary<string, Action<Agency, Citation>> QueryMap = new Dictionary<string, Action<Agency, Citation>>
    {
        { "SQL", QueryOracle},
        { "PIC", QueryPic}
    };


    queryCitation.AgencyCode = agency.AgencyCode;

    QueryMap[agency.ClientDb.Type](agency, queryCitation);
}
2 голосов
/ 25 апреля 2011

ADO.NET имеет набор универсальных классов: DbCommand, DbConnection и т. Д. ..., которые также реализуют другой набор универсальных интерфейсов: IDbCommand, IDbConnection и т. Д. *

Так что вы можете использовать их,но это может стать довольно сложным в конце.Преимущество вашего решения в том, что оно очень читабельное.Плюс, возможно, база данных выбора не имеет какого-либо провайдера ADO.NET ...

PS: я бы заменил тип свойства Type и использовал бы вместо него перечисление.

0 голосов
/ 25 апреля 2011

Существует два решения ООП полиморфизм и Шаблон посетителя .

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...