Рефакторинг c #: как удалить дублирующийся код, когда свойства для обновления отличаются в каждом случае - PullRequest
2 голосов
/ 07 сентября 2011

После недолгого взлома прототипа у меня появилось несколько методов, которые обновляют логические флаги на объекте, а затем обновляют интерфейс и выполняют некоторую обработку на основе нового значения. Они в значительной степени одинаковы - но значение, которое они обновляют, отличается

например - представьте, что у нас есть куча цветных блоков для обновления - у меня могут быть некоторые методы, которые выглядят так:

        protected void SetBlueBoxVisibility(bool blueBoxVisibility)
    {
        Project project = LoadProject();
        project.ShowBlueBox = blueBoxVisibility
        ReDrawSomeThings();
        CalcualteSomeStuff();
        Project.UpdateBoxStatus();
        SaveProject(project);
        ShowBlueBoxPanel(blueBoxVisibility);
        RaiseStatusUpdated();
    }

    protected void SetRedBoxVisibility(bool redBoxVisibility)
    {
        Project project = LoadProject();
        project.ShowRedBox = redBoxVisibility
        ReDrawSomeThings();
        CalcualteSomeStuff();
        Project.UpdateBoxStatus();
        SaveProject(project);
        ShowRedBoxPanel(redBoxVisibility);
        RaiseStatusUpdated();

    }       

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

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

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

Я считал возможным, что следующее может быть в правой строке - но я не знаю, как указать универсальному методу, с каким свойством работать - [Project Variable To Update]

        protected void SetRedBoxVisibility(bool redBoxVisibility)
    {
        SetGenericBoxVisibility([Project Variable To Update],redBoxVisibility)
        ShowRedBoxPanel(redBoxVisibility);
        RaiseStatusUpdated();   
    }

    protected void SetBlueBoxVisibility(bool blueBoxVisibility)
    {
        SetGenericBoxVisibility([Project Variable To Update],blueBoxVisibility)
        ShowBlueBoxPanel(blueBoxVisibility);
        RaiseStatusUpdated();   
    }

    protected void SetGenericBoxVisibility([Project Variable To Update], boxVisibility)
    {
        Project project = LoadProject();
        project.**[Project Variable To Update]** = boxVisibility
        ReDrawSomeThings();
        CalcualteSomeStuff();
        Project.UpdateBoxStatus();
        SaveProject(project);
    }

Любые указатели относительно того, как обращаться с такими вещами, были бы полезны:)

Ответы [ 3 ]

3 голосов
/ 07 сентября 2011

Ну, вы могли бы извлечь это так:

protected void SetGenericBoxVisibility(Action<Project> propertySetter,
                                       Action<bool> panelShower,
                                       bool boxVisibility)
{
    Project project = LoadProject();
    propertySetter(project);
    ReDrawSomeThings();
    CalculateSomeStuff();
    Project.UpdateBoxStatus();
    SaveProject(project);
    panelShower();
    RaiseStatusUpdated();
}

Тогда:

protected void SetBlueBoxVisibility(bool blueBoxVisibility)
{
    SetGenericBoxVisibility(project => project.ShowBlueBox = blueBoxVisibility,
                            () => ShowBlueBoxPanel(blueBoxVisibility));
}

protected void SetRedBoxVisibility(bool redBoxVisibility)
{
    SetGenericBoxVisibility(project => project.ShowRedBox = redBoxVisibility,
                            () => ShowRedBoxPanel(redBoxVisibility));
}

Это не ужасно приятно, правда ...

1 голос
/ 07 сентября 2011

Я думаю, что для реального рефакторинга вам нужно создать интерфейс IBox.По сути, этот интерфейс действует как контракт, определяющий, какие методы и свойства должны иметь как минимум все объекты Box.

interface IBox {
 //your generic properties and method stubs
 Bool visibility;
}

Теперь реализуйте интерфейс для каждого из ваших «блоков»

class blueBox : IBox
{
 //here you will have your concrete implementations of the above methods and properties
public Bool visibility   {get; set;} // this doesn't make sense with auto getter setters. you would need to write your bluebox specific getter and setters

}

class redBox : IBox
{
//more concrete implementation

}


public myMethod_To_Do_Stuff(IBox myBox) { // see how I am passing the interface not the conrete classes

myBox.visibility = true;

}
1 голос
/ 07 сентября 2011

Я думаю, что у вас могут быть большие проблемы - один метод для обновления просто не подходит.У вас есть SetGenericBoxVisibility, но затем отмените любую хорошую работу, продолжая использовать методы Set * BoxVisibility.Я не знаю, какую технологию вы используете - если WPF заглянет в MVVM, вы можете просто обновить ваши ViewModels.Если это WinForms, вы должны создать какой-то словарь, возможно - Dictionary<BoxType, Box> _boxLookup, где BoxType - это перечисление типов, которые вы определяете.Затем, чтобы установить видимость блока, вы делаете _boxLookup[BoxType.Red].Property = value;, или у вас могут быть методы для управления блоком, принимающие параметр BoxType.

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

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