шаблон проектирования для удаления нескольких предложений if / else со связанными объектами - PullRequest
3 голосов
/ 18 февраля 2010

Я унаследовал следующий (ужасный) код, и мне интересно, как лучше его реорганизовать.

В кодовой базе есть большие предложения if / else, одно из которых похоже на приведенное ниже:

public class BaseResultItem
{
    public int Property1 { get; set; }
}

public class ResultItem1 : BaseResultItem
{
    public int Property2 { get; set; }
}

public class ResultItem2 : BaseResultItem
{
    public int Property3 { get; set; }
}

public class BaseHistoryItem
{
    public int Property1 { get; set; }
}

public class HistoryItem1 : BaseHistoryItem
{
    public int Property2 { get; set; }
}

public class HistoryItem2 : BaseHistoryItem
{
    public int Property3 { get; set; }
}

public class HistoryBuilder
{
    public BaseHistoryItem BuildHistory(BaseResultItem result)
    {
        BaseHistoryItem history = new BaseHistoryItem            
        {
            Property1 = result.Property1
        };

        if (result is ResultItem1)
        {
            ((HistoryItem1)history).Property2 = ((ResultItem1)result).Property2;
        }
        else if (result is ResultItem2)
        {
            ((HistoryItem2)history).Property3 = ((ResultItem2)result).Property3;
        }

        return history;
    }
}

Обратите внимание, что это упрощенный пример, и в реальном коде задействовано гораздо больше классов. Схожие пункты if / else повсюду.

Я смотрел на абстрактный шаблон фабрики, но у меня возникли некоторые проблемы.

По сути, я предполагаю, что во избежание проблем с if / else мне нужно передать фактические типы dervied. Таким образом, BuildHistory не должен использовать базовые типы и, возможно, должно быть несколько методов, по одному на каждый производный тип?

Ответы [ 3 ]

1 голос
/ 22 февраля 2010

Если вы не можете изменить классы DTO, возможно, вы можете попытаться создать подкласс HistoryBuilder для работы с различными подклассами.Затем вы используете соответствующий HistoryBuilderX для создания HistoryItem из ResultItem.Тогда возникает вопрос, как получить соответствующий HistoryBuilderX для предоставленного ResultItem.

Тем не менее, если вы не можете изменить класс BaseResultItem для включения функции GetBuilder, вам нужно использовать некоторую конструкцию if..else if ..который проверяет классы ваших ResultItems.

Или вы создаете Реестр, в котором каждый класс ResultItem зарегистрирован в соответствующем классе HistoryBuilderX.Но это может быть излишним.

1 голос
/ 18 февраля 2010

Общий «шаблон проектирования» - это просто использование ориентации объекта с полиморфизмом вместо проверки типов. Таким образом: метод BuildHistory внутри BaseResultItem, переопределенный потомками.

Любой код, который проверяет запах конкретного типа объекта (в смысле рефакторинга). Поддержка OO для разных типов - вот что такое OO.

0 голосов
/ 22 февраля 2010

Используйте полиморфизм , чтобы удалить проверки типов.

if (result is ResultItem1)
{
    ((HistoryItem1)history).Property2 = ((ResultItem1)result).Property2;
}

становится тогда чем-то вроде

result.addToHistory( history );

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

public class Visitor {
     History history;
     public visit ( ResultItem1 item )  { ... }
     public visit ( ResultItem2 item )  { ... }
     ...
}

public class ResultItem1 {
     public accept( Visitor v ) { v.visit( this ); }
}

Проверка типа снимается двойной отправкой в ​​посетителе, что несколько элегантнее.

Я не совсем понял, как различные виды истории связаны с различными видами предметов. Так что это всего лишь набросок возможных направлений для подражания.

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