The operation can be described as:
public interface ITextDecorator
{
string GetString(string input);
}
This encapsulates the how (Web.config, XML, etc.) and emphasizes the what (decorating a string).
Then, any class which might need to decorate text can take an instance of that interface:
public class Foo
{
private ITextDecorator _textDecorator;
public Foo(ITextDecorator textDecorator)
{
_textDecorator = textDecorator;
}
public void Bar(string text)
{
text = _textDecorator.GetString(text);
// ...
}
}
Example implementations of ITextDecorator
might be:
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;
}
}
An example usage of these classes might be:
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");
Notice the decoupling of the exclamation point appending from its conditional invocation. Both classes can now be reused independent of the other. This design style of fine-grained objects works best with an Inversion of Control (IoC) container. However, it is not required.