Я пытаюсь придумать очень аккуратный способ изменить существующий класс. Я попытаюсь объяснить, что я придумал, используя этот пример;Переопределение метода класса с помощью класса-обертки
abstract class AbstractX
{
public abstract string X();
protected internal abstract int Y();
}
// Execute all methods on another instance of AbstractX
// This is why the method(s) are 'protected *internal*'
class WrappedX : AbstractX
{
AbstractX _orig;
public WrappedX(AbstractX orig)
{
_orig = orig;
}
public override string X()
{
return _orig.X();
}
protected internal override int Y()
{
return _orig.Y();
}
}
// The AbstractX implementation I start with
class DefaultX : AbstractX
{
public override string X()
{
// do stuff
// call Y, note that this would never call Y in WrappedX
var y = Y();
return y.ToString();
}
protected internal override int Y()
{
return 1;
}
}
// The AbstractX implementation that should be able to alter *any* other AbstractX class
class AlteredX : WrappedX
{
public AlteredX(AbstractX orig)
:base(orig)
{
}
protected internal override int Y()
{
Console.WriteLine("Sweet, this can be added to any AbstractX instance!");
return base.Y();
}
}
Правильно, так что я намерен использовать это;
AbstractX x = new DefaultX();
x = new AlteredX(x);
Console.WriteLine(x.X()); // Should output 2 lines
Или отойти от абстрактного примера на второй и сделать его более конкретным (должно быть понятно);
FileWriterAbstract writer = new FileWriterDefault("path/to/file.ext");
writer = new FileWriterSplit(writer, "100MB");
writer = new FileWriterLogged(writer, "path/to/log.log");
writer.Write("Hello");
Но (вернемся к абстрактному примеру) это не сработает. Момент AlteredX.X()
называется (не переопределяется) она переходит к WrappedX.X()
, который, конечно, работает DefaultX.X()
, который использует это собственныйY()
метод, а не один я определил в AlteredX.
Он даже не знает, она существует.
Я надеюсь, что это очевидно, почему я хочу, чтобы это сработало, но я объясню далее, чтобы убедиться;
Если я не использую WrappedX
к созданному AlteredX,
AlteredX не будет «applyable» в любой AbstractX экземпляр, таким образом, что делает что-то вроде FileWriter
выше невозможно. Вместо;
FileWriterAbstract
FileWriterDefault : FileWriterAbstract
FileWriterWrap : FileWriterAbstract
FileWriterSplit : FileWriterWrap
FileWriterLogged : FileWriterWrap
Это стало бы;
FileWriterAbstract
FileWriterDefault : FileWriterAbstract
FileWriterSplit : FileWriterDefault
// Implement Logged twice because we may want to use it with or without Split
FileWriterLogged : FileWriterDefault
FileWriterLoggedSplit : FileWriterSplit
И если я тогда создал новый, я должен был бы реализовать его в 4 раза, потому что я хочу его пригодным для использования с;
Default
Split
Logged
Split+Logged
И так далее ...
Так с этим в виду, что это лучший способ для достижения этой цели? Лучшее, что я мог придумать (непроверенный);
class DefaultX : AbstractX
{
protected internal override Func<string> xf { get; set; }
protected internal override Func<int> yf { get; set; }
public DefaultX()
{
xf = XDefault;
yf = YDefault;
}
public override string X()
{
return xf();
}
protected override int Y()
{
return yf();
}
string XDefault()
{
var y = Y();
return y.ToString();
}
int YDefault()
{
return 1;
}
}
class AlteredX : WrappedX
{
Func<int> _yfOrig { get; set; }
public AlteredX()
{
// I'm assuming this class member doesn't get overwritten when I set
// base.yf in the line below.
_yfOrig = base.yf;
base.yf = YAltered;
}
private int YAltered()
{
Console.WriteLine("Sweet, this can be added to any AbstractX instance!");
return yfOrig();
}
}
Даже если это действительно работает, кажется действительно беспорядочным ... есть ли у кого-нибудь предложения?
Что вы придумали, как выглядит шаблон Decorator, http://en.wikipedia.org/wiki/ Decorator_pattern – tvanfosson
@Alireza Я знаю, это не меняет того факта, что я ищу решение проблемы. – natli
@tvanfosson Да, похоже. Эта страница wiki показывает только примеры, которые не пытаются переопределить определенные методы, вызываемые общедоступными методами, поэтому мой вопрос стоит. – natli