Избавление от необходимости проверять значение параметра при каждом использовании объекта. - PullRequest
1 голос
/ 31 мая 2009

Представьте себе приложение, основанное на опциях.

Я хочу добавить восклицательный знак в конец каждой строки (сама по себе, очень легкая задача). Тем не менее, у меня есть опция в файле web.config или в файле XML, поэтому, если опция верна, восклицательный знак добавляется, в противном случае - нет.

Я знаю, как проверить web.config или xml-файл для значения параметра, однако, каков наилучший способ сделать это? В случае строки она будет активно использоваться в любой программе.

Я мог бы написать:

if (ExclamationIsSet)
{
// Append here
}

// Otherwise it isn't set, so don't.

Однако, это не практично для большой (или даже маленькой) кодовой базы. Есть ли способ избавиться от этой ручной проверки? Я слышал, что AOP или атрибуты могут решить эту проблему, но я не видел примера.

Какими методами можно решить эту проблему?

Ответы [ 3 ]

4 голосов
/ 31 мая 2009

Операция может быть описана как:

public interface ITextDecorator
{
    string GetString(string input);
}

Инкапсулирует how (Web.config, XML и т. Д.) И подчеркивает what (украшение строки).

Тогда любой класс, которому может потребоваться оформление текста, может получить экземпляр этого интерфейса:

public class Foo
{
    private ITextDecorator _textDecorator;

    public Foo(ITextDecorator textDecorator)
    {
        _textDecorator = textDecorator;
    }

    public void Bar(string text)
    {
        text = _textDecorator.GetString(text);

        // ...
    }
}

Примером реализации ITextDecorator может быть:

public sealed class ExclamationPointTextDecorator : ITextDecorator
{
    public string GetString(string input)
    {
        return input + "!";
    }
}

public sealed class ConditionalTextDecorator : ITextDecorator
{
    private Func<bool> _condition;
    private ITextDecorator _innerTextDecorator;

    public ConditionalTextDecorator(Func<bool> condition, ITextDecorator innerTextDecorator)
    {
        _condition = condition;
        _innerTextDecorator = innerTextDecorator;
    }

    public string GetString(string input)
    {
        return _condition() ? _innerTextDecorator.GetString(input) : input;
    }
}

Примером использования этих классов может быть:

var textDecorator = new ConditionalTextDecorator(
    () => true,  // Check Web.config, an XML file, or any other condition
    new ExclamationPointTextDecorator());

var foo = new Foo(textDecorator);

foo.Bar("Test");

Обратите внимание на разделение восклицательного знака, добавляемое к его условному вызову. Оба класса теперь можно использовать независимо друг от друга. Этот стиль разработки мелкозернистых объектов лучше всего работает с контейнером Inversion of Control (IoC). Однако это не обязательно.

2 голосов
/ 31 мая 2009

Вы можете заключить чек в метод:

private string SomeGoodMethodName(string text)
{
    if (text == null || text.EndsWith("!")) { return text; }

    return ConfigurationManager.AppSettings["addExclamation"] == "1" ? text + "!" : text;
}

... а затем извлеките ваши строки с помощью этого метода. При необходимости вы можете посмотреть на производительность вокруг ConfigurationManager.AppSettings и, возможно, сохранить ее как логическое значение для проверки вместо этого.

2 голосов
/ 31 мая 2009

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

WriteOutput(someValue); // presumably with some other args

, где WriteOutput несет ответственность за проверку этого флага - то есть он не находится в лоте мест. Вы также можете обнаружить, что методы расширения C # 3.0 играют определенную роль; например, если вы пишете в TextWriter:

public static void WriteWithMarker(this TextWriter writer, SomeType value) {
    writer.Write(value);
    if(ExclamationIsSet) writer.Write(SomeExtraStuff);
}

тогда ваш код просто (всегда) вызывает output.WriteWithMarker(value); - работа выполнена.

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

public static class MyUtiltiyClass {
    private static readonly bool exclamationIsSet;
    public static bool ExclamationIsSet {get{return exclamationIsSet;}}
    static MyUtiltiyClass() {
        exclamationIsSet = FindWhetherTheFlagIsSet();
    }
    public static void WriteWithMarker(this TextWriter writer, SomeType value) {
        writer.Write(value);
        if(ExclamationIsSet) writer.Write(SomeExtraStuff);
    }
    //etc
}

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

...