【发布时间】:2013-09-08 15:24:38
【问题描述】:
我正在尝试想出一种非常巧妙的方法来改变现有的课程。我将尝试用这个例子来解释我的想法;
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 将不会“适用于”任何 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();
}
}
即使这确实有效,但看起来真的很乱……有人有什么建议吗?
【问题讨论】:
-
你想出的看起来像装饰者模式,en.wikipedia.org/wiki/Decorator_pattern
-
@Alireza 我知道,这并不能改变我正在寻找问题解决方案的事实。
-
@tvanfosson 是的,看起来像。该维基页面仅显示不尝试覆盖公共方法调用的特定方法的示例,所以我的问题是。
标签: c# inheritance architecture polymorphism