1

想象一个基于选项的应用程序。

我想在每个字符串的末尾添加一个感叹号(这本身就是一项非常简单的任务)。但是,我在 web.config 或 XML 文件中有一个选项,因此如果该选项为真,则附加感叹号,否则不附加。

我知道如何检查 web.config 或 xml 文件的设置值,但是,最好的方法是什么?在字符串的情况下,它将在任何程序中大量使用。

我可以写:

if (ExclamationIsSet)
{
// Append here
}

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

但是,这对于大型(甚至小型)代码库是不切实际的。有没有办法摆脱这种手动检查?我听说 AOP 或属性可能能够解决这个问题,但我还没有看到一个例子。

有哪些方法可以解决这个问题?

4

3 回答 3

4

该操作可以描述为:

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

这封装了方式(Web.config、XML 等)并强调了内容(装饰字符串)。

然后,任何可能需要装饰文本的类都可以采用该接口的实例:

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");

请注意附加的感叹号与其条件调用的分离。这两个类现在可以独立于另一个类重用。这种细粒度对象的设计风格最适用于控制反转 (IoC) 容器。但是,这不是必需的。

于 2009-05-30T21:31:11.173 回答
2

我可能不会在这里使用 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);- 工作完成。

我可能还会通过在初始化时存储这个值来确保我最小化影响 - 静态构造函数非常方便:

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
}

也许有了更多关于你目前在做什么和在哪里做这件事的背景,它可能会变得更清楚......

于 2009-05-30T21:30:00.880 回答
2

您可以将检查包装到一个方法中:

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

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

...然后通过该方法获取您的字符串。如果需要,您可能希望查看 ConfigurationManager.AppSettings 的性能,并可能将其存储为布尔值以进行测试。

于 2009-05-30T21:31:23.107 回答