B 类继承自 A 类, β类继承自α类. 同时α作为 A 类的字段, β作为 B 类的字段. 现希望 B 实例调用父类方法(该父类方法调用了字段α)时, 能使用自身环境中的β实例而非α实例(因为α对 B 没有意义, 虽然从父类继承, 但完全不使用, 只使用β)
于是考虑将字段α设为 virtual:
public class Alpha
{
public virtual void printSelf()
{
print("this is alpha");
}
}
public class Beta: Alpha
{
public override void printSelf()
{
print("this is beta");
}
}
public class A
{
public virtual Alpha alpha
{
get => _alpha;
set => _alpha = value;
}
private Alpha _alpha
public virtual void PrintSelf()
{
alpha.printSelf();
}
}
public class B: A
{
public override Alpha alpha
{
get => _beta;
set{}
}
// public?
private Beta _beta;
}
public class Main
{
var b = new B();
b.PrintSelf();
}
请问这样设计合理吗? 另外, 为了访问β实例中的非继承字段, B 类中的β字段必须设为 public, 这样会带来额外的问题吗?
还是说这种需求就是不合理? 已经有点绕晕了现在. 这种"嵌套的继承关系"有没有专业点的称呼?
public class Alpha
{
public virtual void printSelf()
{
print("this is alpha");
}
}
public class Beta: Alpha
{
public override void printSelf()
{
print("this is beta");
}
}
public interface IPrint
{
void PrintSelf();
}
public class A: IPrint
{
public virtual Alpha alpha
{
get => _alpha;
set => _alpha = value;
}
private Alpha _alpha
public void PrintSelf()
{
alpha.printSelf();
}
}
public class B: A
{
public override Alpha alpha
{
get => _beta;
set{}
}
// public?
private Beta _beta;
}
public class Main
{
private IPrint test;
public void Test()
{
test = new B();
test.PrintSelf();
}
}
v3
public interface IContent
{
string Content {get; set;}
}
public class Alpha: IContent
{
public string Content {get; set;} = "this is alpha";
}
public class Beta: Alpha
{
public string Content {get; set;} = "this is beta";
}
public interface IPrint
{
void PrintSelf();
}
public class A: IPrint
{
public A()
{
content = new Alpha();
}
public IContent content;
public void PrintSelf()
{
print(content.Content);
}
}
public class B: A
{
public B()
{
content = new Beta();
}
}
public class Main
{
private IPrint test;
public void Test()
{
test = new B();
// 期望输出: this is beta
test.PrintSelf();
}
}
v4
// 数据类
public interface IText
{
string Text {get; set;}
}
public class Alpha: IText
{
public string Text {get; set;} = "this is alpha";
}
public class Beta: Alpha
{
public string Text {get; set;} = "this is beta";
}
// 使用类
public interface IPrint
{
void PrintSelf();
}
public interface IContent
{
IText Content {get; set;}
}
public class A: IPrint, IContent
{
public A()
{
Content = new Alpha();
}
public IText Content {get; set;}
public void PrintSelf()
{
print(Content.Text);
}
}
public class B: A
{
public B()
{
Content = new Beta();
}
}
// 调用
public class Main
{
private IPrint test;
public void Test()
{
test = new B();
// 期望输出: this is beta
test.PrintSelf();
}
}
1
cxe2v 343 天前
printSelf 方法传入一个实例参数,就可以 B 使用β实例,A 使用α实例
|
2
GodOfParentheses OP @cxe2v 这样的话得靠调用者手动传入α或β实例? 但是调用者往往连 a 实例和 b 实例都不区分, 而α/β又是和 A/B 高度绑定的.
|
3
cxe2v 342 天前
@GodOfParentheses 调用者为啥不区分这个实例呢,不区分的话,A 跟 B 内部都用β类型就行了
|
4
GodOfParentheses OP @cxe2v 不好意思, 例子写的不对, 请看新的代码. A/B 类存在接口继承, 调用者持有接口实例, 所以不区分 A/B.
我好像有点明白了, 如果把α也放到接口里是不是就等价于现在的效果? |
5
cxe2v 342 天前
接口继承的话,A,B 互不影响,实现 PrintSelf 是 AB 各自在内部实现的,你想怎么写怎么写都可以
|
6
GodOfParentheses OP 根据新理解重新写了第三个版本. 需求的核心是: 父子类中字段 X 有着不同的实现, 希望子实例调用继承自父类的方法 Y 时(Y 方法引用 X 字段), 使用 X 字段自己的实现而非父类的实现.
刚开始纠结的字段 X 在父子类中的继承关系其实不重要. C#的多态机制可以实现这点, 问题是怎么写更好, 不知道 v3 这种写法还能改进不. |
7
GodOfParentheses OP v5. 我悟了, 这其实就是个 Liskov 和 Open/Close 原则的应用, "继承抽象而不是继承具体". 又是被自己菜哭的一天.
|