派生具有不同类型的封装类

时间:2018-06-16 05:36:42

标签: c# inheritance

我想覆盖不同类型的属性。

假设我有一个继承自 Point2D 的Class Point3D 以及从 Drawing2D 继承的Class Drawing3D

我希望Drawing2D和Drawing3D这两个类都具有相同的属性名称Points ,它将是Drawing2D的Point2D列表,以及Drawing3D的Point3D列表。

具有相同的属性名称,我希望Drawing3D可以在属性Points上受益于Drawing2D方法。 事情是我不能使用覆盖,因为类型不同。关键字 new 不起作用,因为Drawing3D似乎有2个属性点(Point2D列表和Point3D列表)。 在Drawing3D上使用基本方法,它将通过Point2D列表。

我的2D课程:

class Point2D
{
    public int X { get; set; }
    public int Y { get; set; }

    public Point2D(int x, int y)
    {
        X = x;
        Y = y;
    }

    public virtual void Print()
    {
        Console.WriteLine($"2D Point: [{X}, {Y}]");
    }
}

class Drawing2D
{
    public string Name { get; set; }
    public virtual List<Point2D> Points { get; set; }

    public Drawing2D(string name)
    {
        Name = name;
        Points = new List<Point2D>();
    }

    public void Print()
    {
        Console.WriteLine($"Drawing name: {Name}");
        foreach (var point in Points)
            point.Print();
    }
}

基于2D类的我的3D类

class Point3D:Point2D
{
    public int Z { get; set; }

    public Point3D(int x, int y, int z):base(x,y)
    {
        Z = z;
    }

    public override void Print()
    {
        Console.WriteLine($"3D Point: [{X}, {Y}, {Z}]");
    }
}

class Drawing3D : Drawing2D
{
    public new List<Point3D> Points { get; set; }

    public Drawing3D(string name) : base(name)
    {
        Points = new List<Point3D>();
    }
}

我的主程序

class Program
{
    static void Main(string[] args)
    {
        Drawing3D myDrawing = new Drawing3D("Sketch");
        myDrawing.Points.Add(new Point3D(1, 2, 3));
        myDrawing.Points.Add(new Point3D(4, 5, 6));
        myDrawing.Print();

        Console.ReadKey();
    }
}

结果是它不打印任何一点。基本方法Print()遍历Point2D列表,而不是Point3D。

希望你们能帮助我。 我喜欢优雅的代码,可能是我的方法不正确...

干杯

3 个答案:

答案 0 :(得分:1)

如果您必须为上述示例做,那么您可以这样做。

public abstract class Point
    {
       public abstract void Print();
    }

    class Point2D : Point
    {
        public int X { get; set; }
        public int Y { get; set; }

        public Point2D(int x, int y)
        {
            X = x;
            Y = y;
        }

        public override void Print()
        {
            Console.WriteLine($"2D Point: [{X}, {Y}]");
        }
    }

    class Point3D : Point2D
    {
        public int Z { get; set; }

        public Point3D(int x, int y, int z) : base(x, y)
        {
            Z = z;
        }

        public override void Print()
        {
            Console.WriteLine($"3D Point: [{X}, {Y}, {Z}]");
        }
    }


    class Drawing<T> where T:Point
    {
        public string Name { get; set; }
        public virtual List<T> Points { get; set; }

        public Drawing(string name)
        {
            Name = name;
            Points = new List<T>();
        }

        public void Print()
        {
            Console.WriteLine($"Drawing name: {Name}");
            foreach (var point in Points)
                point.Print();
        }
    }

    class Drawing3D : Drawing<Point3D>
    {
        public Drawing3D(string name) : base(name)
        {
            Name = name;            
        }
    }

    class Drawing2D : Drawing<Point2D>
    {
        public Drawing2D(string name) : base(name)
        {
            Name = name;
        }
    }

答案 1 :(得分:1)

在你的问题中,你有覆盖方法将Point2D类打印到Point3D类,这样做很好。

意味着您在Print中专门实施了功能Point3D,该功能与Point2D的{​​{1}}功能完全相同,并且应打印有关3D点的信息。

但是你在Print类中继承了Print类的方法Drawing2D,这意味着从Drawing3D的对象调用Print方法将执行方法Drawing3D

现在正在研究Drawring2D的方法,您正在打印有关Drawing2D类点的信息(Drawing2D有自己的点列表,哪些点不同于Drawing2D点的列表{ {1}}有)。

所以当您从Drwaing3D调用Drwaing3D方法时设置Print点后,您正在调用Drawing3D Print方法,该方法会尝试打印关于它自己的点的信息(我们没有设置 - 因为我们设置了Drawing2D)。

所以你可以做的是,

由于您拥有Drawing3D类的过度使用方法,因此您还应该在Point类中覆盖Print类的Drawing2D方法。

如下所示。

Drwaing3D

此处class Drawing2D { public string Name { get; set; } public virtual List<IPoint> Points { get; set; } public Drawing2D(string name) { Name = name; Points = new List<IPoint>(); } public virtual void Print() { Console.WriteLine("Drawing name: {"+Name+"}"); foreach (var point in Points) point.Print(); } } class Drawing3D : Drawing2D { public new List<IPoint> Points { get; set; } public Drawing3D(string name) : base(name) { Points = new List<IPoint>(); } public override void Print() { Console.WriteLine("Drawing name: {"+Name+"}"); foreach (var point in Points) point.Print(); } } IPoint类应实现的接口。

Point

UPDATE (这将是继承而不是覆盖)

但是高级代码可以正常工作。但我并不认为它完美无瑕。

第一点:点总是1维,所以不应该有2D点或3D点。

相反,只能绘制2D或3D(这里基于它的点数)。

另外,在两个绘图类中,我们都有耦合的打印信息代码。这是重复的,我们可以将它们放在一个地方。

我建议改变代码如下。

单点类(此处不需要多重实现或继承)

public interface IPoint
{
    void Print();
}

class Point2D : IPoint
{
public int X { get; set; }
public int Y { get; set; }

public Point2D(int x, int y)
{
    X = x;
    Y = y;
}

public virtual void Print()
{
    Console.WriteLine("2D Point: [{"+X+"}, {"+Y+"}]");
}
}

class Point3D:Point2D, IPoint
{
    public int Z { get; set; }

    public Point3D(int x, int y, int z):base(x,y)
    {
        Z = z;
    }

    public override void Print()
    {
        Console.WriteLine("3D Point: [{"+X+"}, {"+Y+"}, {"+Z+"}]");
    }
}

基础绘图类,它具有打印功能和其他常用属性,如点列表和名称(这将是2D或3D类的常见)。

class Point
{
    public int Val { get; set; }
    public string CordinateName {get; set;}
    public Point(int val, string cordinateName)
    {
        Val = val;
        CordinateName = cordinateName;
    }

    public virtual void Print()
    {
        Console.WriteLine(CordinateName + " Point: [{"+Val+"}]");
    }
}

从Drawing中得到的2D绘图非常清楚。

class Drawing
{
    public List<Point> Points { get; set; }
    public string Name {get; set;}
    public Drawing(string name)
    {
        Name = name;
        Points = new List<Point>();
    }

    public void Print()
    {
        Console.WriteLine("Drawing name: {"+Name+"} ");

        foreach (var point in Points)
            point.Print();
    } 
}

3D绘图源自2D绘图,因为3D绘图保存了2D绘图的所有特征(此处为X和Y点以及Drawing类的继承特征),还有一些专用于3D绘图的其他特征(第3点)。 / p>

class Drawing2D : Drawing
{
    public Drawing2D(string name, int xPoint, int yPoint) : base (name)
    {
        Points.Add(new Point(xPoint, "X"));
        Points.Add(new Point(yPoint, "Y"));
    }
}

最后是你的呼叫机制。

class Drawing3D : Drawing2D
{
    public Drawing3D(string name, int xPoint, int yPoint, int zPoint) : base(name, xPoint, yPoint)
    {
       Points.Add(new Point(zPoint, "Z"));
    }
}

答案 2 :(得分:0)

Point2DPoint3D实现相同的界面,让我们说IPoint。然后在这两个类中,您可以创建IPoint类型的字段。然后,您可以保留对两种类型对象的引用:Point2DPoint3D

这是一般规则:

  

Porgram接口,而不是实现。

完全适用于此。这只是设计原则中的一个,您可能需要阅读它。

在界面中,您将实现方法Print()(将在具体类中正确实现),绘图类中的方法Print()应该将任务委派给IPoint.Print()

以下是根据我的评论重构的代码:

public interface IPoint
{
    void Print();
}

class Point2D : IPoint
{
    public int X { get; set; }
    public int Y { get; set; }

    public Point2D(int x, int y)
    {
        X = x;
        Y = y;
    }

    public void Print()
    {
        Console.WriteLine($"2D Point: [{X}, {Y}]");
    }
}

class Point3D : IPoint
{
    public int X { get; set; }
    public int Y { get; set; }
    public int Z { get; set; }

    public Point3D(int x, int y, int z)
    {
        X = x;
        Y = y;
        Z = z;
    }

    public void Print()
    {
        Console.WriteLine($"3D Point: [{X}, {Y}, {Z}]");
    }
}

class Drawing2D
{
    public string Name { get; set; }
    public List<IPoint> Points { get; set; }

    public Drawing2D(string name)
    {
        Name = name;
        Points = new List<IPoint>();
    }

    public void Print()
    {
        Console.WriteLine($"Drawing name: {Name}");
        foreach (var point in Points)
            point.Print();
    }
}

class Drawing3D : Drawing2D
{
    public Drawing3D(string name) : base(name) { }
}