
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 2023-12-14 16:37:00 +08:00 printSelf 方法传入一个实例参数,就可以 B 使用β实例,A 使用α实例 |
2 GodOfParentheses OP @cxe2v 这样的话得靠调用者手动传入α或β实例? 但是调用者往往连 a 实例和 b 实例都不区分, 而α/β又是和 A/B 高度绑定的. |
3 cxe2v 2023-12-15 11:29:59 +08:00 @GodOfParentheses 调用者为啥不区分这个实例呢,不区分的话,A 跟 B 内部都用β类型就行了 |
4 GodOfParentheses OP @cxe2v 不好意思, 例子写的不对, 请看新的代码. A/B 类存在接口继承, 调用者持有接口实例, 所以不区分 A/B. 我好像有点明白了, 如果把α也放到接口里是不是就等价于现在的效果? |
5 cxe2v 2023-12-15 17:23:54 +08:00 接口继承的话,A,B 互不影响,实现 PrintSelf 是 AB 各自在内部实现的,你想怎么写怎么写都可以 |
6 GodOfParentheses OP 根据新理解重新写了第三个版本. 需求的核心是: 父子类中字段 X 有着不同的实现, 希望子实例调用继承自父类的方法 Y 时(Y 方法引用 X 字段), 使用 X 字段自己的实现而非父类的实现. 刚开始纠结的字段 X 在父子类中的继承关系其实不重要. C#的多态机制可以实现这点, 问题是怎么写更好, 不知道 v3 这种写法还能改进不. |
7 GodOfParentheses OP v5. 我悟了, 这其实就是个 Liskov 和 Open/Close 原则的应用, "继承抽象而不是继承具体". 又是被自己菜哭的一天. |