简体   繁体   English

C#抽象类具有另一个抽象类对象

[英]C# Abstract class has another abstract class object

I have few classes representing some measured data, at first ICut abstract class with derived RoundCut and SquareCut like this: 我很少代表一些测量数据的类,起初, ICut抽象类具有派生的RoundCutSquareCut如下所示:

public abstract class ICut
{
}

public class RoundCut : ICut
{
    DoSomeWithRoundCut(){}
}

public class SquareCut : ICut
{
    DoSomeWithSquareCut(){}
}

Of course it contains some implementation but it isn't important for this question. 当然,它包含一些实现,但是对于这个问题并不重要。 ICut is abstract class instead of interface because it has some implemetation itself. ICut是抽象类而不是接口,因为它本身具有一些实现。

Then, here are classes representing set of ICut data, again base abstract IRoll and derived RoundRoll and SquareRoll : 然后,这是代表ICut数据集的类,再次基于抽象IRoll以及派生的RoundRollSquareRoll

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;
    }
}

And now, of course I'm not able to reach directly RoundCut or SquareCut extra implementation by calling for example: 而现在,我当然无法通过调用例如以下SquareCut直接达到RoundCutSquareCut额外实现:

IRoll roll = new RoundRoll();
roll.CreateCut();
roll.cuts[0].DoSomeWithRoundRoll();

And I can't use neither: 而且我不能使用:

(roll.cuts[0] as RoundCut).DoSomeWithRoundRoll();

because I generally don't know if which IRoll derivation roll is. 因为我通常不知道哪个IRoll派生roll是。

I'm refactoring huge project where all roll objects were of type RoundRoll and now the other has to be added. 我正在重构一个大型项目,其中所有roll对象均为RoundRoll类型,现在必须添加其他对象。

Maybe I'm missing some kind of suitable design pattern, I'm in the begining of advanced OOP patterns learning curve, and I've been thinking about solution of this problem all the day. 也许我缺少某种合适的设计模式,正处于高级OOP模式学习曲线的开始,并且我一直在全天候在考虑解决此问题的方法。

UPDATE After many experiments, I realized that as a contrary to my primary opinions, I ended up with the solution of @The-First-Tiger with some improvements. 更新经过多次实验,我意识到与我的主要观点相反,我最终对@ The-First-Tiger的解决方案进行了一些改进。 I created simple factory: 我创建了简单的工厂:

// 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();
        }
    }
}

So I can create Cut like: 所以我可以像这样创建Cut:

ICut cut = CutFactory.GetCut(roll.GetShape());

And if needed to have different behavior: 并且如果需要具有不同的行为:

if (cut is RoundCut) 
    (cut as RoundCut).RoundCutSpecificMethod();
else if (cut is SquareCut) 
    (cut as SquareCut).SquareCutSpecificMethod();

One way to work around the problem is to make IRoll generic on the type of its ICut : 解决该问题的一种方法是使IRoll在其ICut类型上ICut

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;
    }
}

Now you can do this: 现在您可以执行以下操作:

public class RoundRoll : AbstractRoll<RoundCut> {
    ...
}

public class SquareRoll : AbstractRoll<SquareCut> {
    ...
}

Note that C# lets you move the boilerplate code to the base class by applying constraints to generic types. 请注意,C#使您可以通过将约束应用于泛型类型来将样板代码移动到基类。

The only remaining issue now is that AbstractRoll is no longer a common interface for RoundRoll and SquareRoll , so you cannot create a collection of rolls. 现在唯一剩下的问题是AbstractRoll不再是RoundRollSquareRoll的通用接口,因此您无法创建纸卷集合。

This problem can be solved by adding a non-generic interface IRoll on top of AbstractRoll class, with the operations that are common to all rolls, and are also independent of the type of the roll's ICut : 可以通过在AbstractRoll类的顶部添加非通用接口IRoll来解决此问题,该接口具有所有卷所共有的操作,并且也与卷的ICut类型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
}

You could rewrite your code using interfaces: 您可以使用以下接口重写代码:

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();

Update 更新资料

If SquareCut and RoundCut have a lot of methods which are not common you can still check for ICuts concrete type and then cast to it: 如果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();
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM