C# Abstract class 有另一个抽象 class 对象
C# Abstract class has another abstract class object
我有几个 classes 表示一些测量数据,首先 ICut
抽象 class 派生 RoundCut
和 SquareCut
像这样:
public abstract class ICut
{
}
public class RoundCut : ICut
{
DoSomeWithRoundCut(){}
}
public class SquareCut : ICut
{
DoSomeWithSquareCut(){}
}
当然它包含一些实现,但对于这个问题来说并不重要。 ICut
是抽象的 class 而不是接口,因为它本身有一些实现。
然后,这里有 classes 表示 ICut
数据集,同样是基础抽象 IRoll
和派生 RoundRoll
和 SquareRoll
:
public abstract class IRoll
{
// list of measured cuts
public List<ICut> cuts;
// Create new cut
public abstract ICut CreateCut();
}
public class RoundRoll : IRoll
{
public RoundRoll ()
{
cuts = new List<RoundCut>();
}
public override ICut CreateCut()
{
RoundCut cut = new RoundCut();
cuts.Add(cut);
return cut;
}
}
public class SquareRoll : IRoll
{
public SquareRoll()
{
cuts = new List<SquareCut>();
}
public override ICut CreateCut()
{
SquareCut cut = new SquareCut();
cuts.Add(cut);
return cut;
}
}
现在,我当然无法通过调用直接达到 RoundCut
或 SquareCut
额外的实现,例如:
IRoll roll = new RoundRoll();
roll.CreateCut();
roll.cuts[0].DoSomeWithRoundRoll();
我两个都不能用:
(roll.cuts[0] as RoundCut).DoSomeWithRoundRoll();
因为我一般不知道是哪个IRoll
推导roll
。
我正在重构一个巨大的项目,其中所有 roll
个对象都是 RoundRoll
类型,现在必须添加另一个。
也许我缺少某种合适的设计模式,我正处于高级 OOP 模式学习曲线的开始,我一直在思考这个问题的解决方案。
更新
经过多次实验,我意识到与我的主要观点相反,我最终得到了@The-First-Tiger 的解决方案并进行了一些改进。我创建了简单的工厂:
// Cut factory
public static class CutFactory
{
// Get new cut by given shape type
public static ICut GetCut(RollShape shape)
{
switch (shape)
{
case RollShape.Round:
return new RoundCut();
case RollShape.Square:
return new SquareCut();
default:
throw new ArgumentException();
}
}
}
所以我可以像这样创建剪辑:
ICut cut = CutFactory.GetCut(roll.GetShape());
如果需要有不同的行为:
if (cut is RoundCut)
(cut as RoundCut).RoundCutSpecificMethod();
else if (cut is SquareCut)
(cut as SquareCut).SquareCutSpecificMethod();
解决该问题的一种方法是在其 ICut
的类型上使 IRoll
通用:
public abstract class AbstractRoll<T> where T : ICut, new {
// list of measured cuts
public List<T> cuts = new List<T>();
// Create new cut
public T CreateCut() {
var res = new T();
curs.Add(res);
return res;
}
}
现在你可以这样做了:
public class RoundRoll : AbstractRoll<RoundCut> {
...
}
public class SquareRoll : AbstractRoll<SquareCut> {
...
}
请注意,C# 允许您通过对泛型类型应用约束将样板代码移动到基 class。
现在唯一剩下的问题是 AbstractRoll
不再是 RoundRoll
和 SquareRoll
的通用接口,因此您无法创建卷集。
这个问题可以通过在 AbstractRoll
class 之上添加一个非通用接口 IRoll
来解决,其中的操作对所有 rolls 都是通用的,也是独立的卷的类型 ICut
:
public interface IRoll {
IEnumerable<ICut> Cuts { get; }
... // add other useful methods here
}
public abstract class AbstractRoll<T> : IRoll where T : ICut, new {
...
public IEnumerable<ICut> Cuts {
get {
return curs.Cast<ICut>();
}
}
... // implement other useful methods here
}
您可以使用接口重写您的代码:
public interface ICut
{
DoSomething();
}
public class RoundCut : ICut
{
DoSomething(){}
}
public class SquareCut : ICut
{
DoSomething(){}
}
public interface IRoll
{
IEnumerable<ICut> Cuts { get; };
ICut CreateCut();
}
public class RoundRoll : IRoll
{
public IEnumerable<ICut> Cuts { get; private set; }
public RoundRoll ()
{
this.Cuts = new List<ICut>();
}
public ICut CreateCut()
{
var cut = new RoundCut();
this.Cuts.Add(cut);
return cut;
}
}
public class SquareRoll : IRoll
{
public IEnumerable<ICut> Cuts { get; private set; }
public SquareRoll ()
{
this.Cuts = new List<ICut>();
}
public ICut CreateCut()
{
var cut = new SquareCut();
this.Cuts.Add(cut);
return cut;
}
}
IRoll roll = new RoundRoll();
var cut = roll.CreateCut();
cut.DoSomething();
更新
如果 SquareCut 和 RoundCut 有很多不常见的方法,您仍然可以检查 ICuts 具体类型,然后转换为它:
IRoll roll = new RoundRoll();
var cut = roll.CreateCut();
if (cut is RoundCut) {
(cut as RoundCut).RoundCutSpecificMethod();
}
else if (cut is SquareCut) {
(cut as SquareCut).SquareCutSpecificMethod();
}
我有几个 classes 表示一些测量数据,首先 ICut
抽象 class 派生 RoundCut
和 SquareCut
像这样:
public abstract class ICut
{
}
public class RoundCut : ICut
{
DoSomeWithRoundCut(){}
}
public class SquareCut : ICut
{
DoSomeWithSquareCut(){}
}
当然它包含一些实现,但对于这个问题来说并不重要。 ICut
是抽象的 class 而不是接口,因为它本身有一些实现。
然后,这里有 classes 表示 ICut
数据集,同样是基础抽象 IRoll
和派生 RoundRoll
和 SquareRoll
:
public abstract class IRoll
{
// list of measured cuts
public List<ICut> cuts;
// Create new cut
public abstract ICut CreateCut();
}
public class RoundRoll : IRoll
{
public RoundRoll ()
{
cuts = new List<RoundCut>();
}
public override ICut CreateCut()
{
RoundCut cut = new RoundCut();
cuts.Add(cut);
return cut;
}
}
public class SquareRoll : IRoll
{
public SquareRoll()
{
cuts = new List<SquareCut>();
}
public override ICut CreateCut()
{
SquareCut cut = new SquareCut();
cuts.Add(cut);
return cut;
}
}
现在,我当然无法通过调用直接达到 RoundCut
或 SquareCut
额外的实现,例如:
IRoll roll = new RoundRoll();
roll.CreateCut();
roll.cuts[0].DoSomeWithRoundRoll();
我两个都不能用:
(roll.cuts[0] as RoundCut).DoSomeWithRoundRoll();
因为我一般不知道是哪个IRoll
推导roll
。
我正在重构一个巨大的项目,其中所有 roll
个对象都是 RoundRoll
类型,现在必须添加另一个。
也许我缺少某种合适的设计模式,我正处于高级 OOP 模式学习曲线的开始,我一直在思考这个问题的解决方案。
更新 经过多次实验,我意识到与我的主要观点相反,我最终得到了@The-First-Tiger 的解决方案并进行了一些改进。我创建了简单的工厂:
// Cut factory
public static class CutFactory
{
// Get new cut by given shape type
public static ICut GetCut(RollShape shape)
{
switch (shape)
{
case RollShape.Round:
return new RoundCut();
case RollShape.Square:
return new SquareCut();
default:
throw new ArgumentException();
}
}
}
所以我可以像这样创建剪辑:
ICut cut = CutFactory.GetCut(roll.GetShape());
如果需要有不同的行为:
if (cut is RoundCut)
(cut as RoundCut).RoundCutSpecificMethod();
else if (cut is SquareCut)
(cut as SquareCut).SquareCutSpecificMethod();
解决该问题的一种方法是在其 ICut
的类型上使 IRoll
通用:
public abstract class AbstractRoll<T> where T : ICut, new {
// list of measured cuts
public List<T> cuts = new List<T>();
// Create new cut
public T CreateCut() {
var res = new T();
curs.Add(res);
return res;
}
}
现在你可以这样做了:
public class RoundRoll : AbstractRoll<RoundCut> {
...
}
public class SquareRoll : AbstractRoll<SquareCut> {
...
}
请注意,C# 允许您通过对泛型类型应用约束将样板代码移动到基 class。
现在唯一剩下的问题是 AbstractRoll
不再是 RoundRoll
和 SquareRoll
的通用接口,因此您无法创建卷集。
这个问题可以通过在 AbstractRoll
class 之上添加一个非通用接口 IRoll
来解决,其中的操作对所有 rolls 都是通用的,也是独立的卷的类型 ICut
:
public interface IRoll {
IEnumerable<ICut> Cuts { get; }
... // add other useful methods here
}
public abstract class AbstractRoll<T> : IRoll where T : ICut, new {
...
public IEnumerable<ICut> Cuts {
get {
return curs.Cast<ICut>();
}
}
... // implement other useful methods here
}
您可以使用接口重写您的代码:
public interface ICut
{
DoSomething();
}
public class RoundCut : ICut
{
DoSomething(){}
}
public class SquareCut : ICut
{
DoSomething(){}
}
public interface IRoll
{
IEnumerable<ICut> Cuts { get; };
ICut CreateCut();
}
public class RoundRoll : IRoll
{
public IEnumerable<ICut> Cuts { get; private set; }
public RoundRoll ()
{
this.Cuts = new List<ICut>();
}
public ICut CreateCut()
{
var cut = new RoundCut();
this.Cuts.Add(cut);
return cut;
}
}
public class SquareRoll : IRoll
{
public IEnumerable<ICut> Cuts { get; private set; }
public SquareRoll ()
{
this.Cuts = new List<ICut>();
}
public ICut CreateCut()
{
var cut = new SquareCut();
this.Cuts.Add(cut);
return cut;
}
}
IRoll roll = new RoundRoll();
var cut = roll.CreateCut();
cut.DoSomething();
更新
如果 SquareCut 和 RoundCut 有很多不常见的方法,您仍然可以检查 ICuts 具体类型,然后转换为它:
IRoll roll = new RoundRoll();
var cut = roll.CreateCut();
if (cut is RoundCut) {
(cut as RoundCut).RoundCutSpecificMethod();
}
else if (cut is SquareCut) {
(cut as SquareCut).SquareCutSpecificMethod();
}