Java中的类和继承-我做错了什么?

Java中的类和继承-我做错了什么?,java,model-view-controller,oop,class,Java,Model View Controller,Oop,Class,我不熟悉类和继承的概念,我想我可能有点困惑。我正在尝试使用MVC设计模式,因此我认为如果我创建一个基本模型类,那么我可以从这个模型继承所有其他模型,以便view类可以接受对任何类型模型的引用。以下是我的尝试: public class SceneControl { SceneView scMaze; SceneView scOptions; Model ms; public SceneControl(ViewPanel view) { this.

我不熟悉类和继承的概念,我想我可能有点困惑。我正在尝试使用MVC设计模式,因此我认为如果我创建一个基本模型类,那么我可以从这个模型继承所有其他模型,以便view类可以接受对任何类型模型的引用。以下是我的尝试:

public class SceneControl {
    SceneView scMaze;
    SceneView scOptions;
    Model ms;

    public SceneControl(ViewPanel view) {
        this.view = view;

        ms = new Maze(31, 20, 5);
        SceneView scMaze = new SceneView(ms);
        ms = new Options(20, 20, 20, 200, 20);
        SceneView scOptions = new SceneView(ms);
...
下面是我的一个扩展模型类:

public class Maze extends Model {
    public int i;

    public Maze(int cols, int rows, int ratio) {
        super(cols, rows, ratio);
        i=77;  // a test- can I access this field from inside SceneView
    }
}
但是当尝试访问SceneView中的额外迷宫字段时,我得到了一个编译器错误

public Model ms;

public SceneView(Model ms) {
    this.ms = ms;
    System.out.println(ms.i);  //gives "connot be resolved or is not a field" error
...

我猜我的物体已经从迷宫变成了模型了?如何将它传递给视图类,就好像它是一个模型,但实际上它仍然是一个迷宫?

您已经在迷宫中定义了I,但试图通过对模型的引用来访问它


您可以将ms强制转换为迷宫并打破各种OOP规则,也可以将其作为模型的一个成员。

您在迷宫中定义了i,但试图通过对模型的引用来访问它

您可以将ms强制转换为迷宫并打破各种OOP规则,或者必须将其作为模型的成员。

由于SceneView构造函数已声明为接受模型参数,因此它只能看到模型中的成员和方法,而不管传递给SceneView的对象是什么特定子类,所以它看不到i数据成员

现在,为什么SceneView需要看到我?如果SceneView真的要在模型的任何子类上工作,它就不能依赖于子类中的任何东西。所以Maze需要被编写来完成Maze特定于i的工作。

因为SceneView构造函数被声明为接受Model的参数,所以它只能看到模型中的成员和方法,而不管传递给SceneView的对象是什么特定的子类,所以它看不到i数据成员


现在,为什么SceneView需要看到我?如果SceneView真的要在模型的任何子类上工作,它就不能依赖于子类中的任何东西。因此,Maze需要被编写来完成与i有关的任何Maze特定的工作。

当传递泛型类型时,继承只对传递的最泛型类型的基本功能起作用。例如,在这种情况下,如果不是每个模型都有公共int;,如果不进行类型转换,您就无法直接访问它。我们稍后将对此进行讨论。此外,在这种特殊情况下,您只能访问模型类中显式定义的函数和变量,因为所有派生类都保证这些函数和变量相同

然而,现在,如果您确实知道您有一个给定类型的特定子类,那么您可以对其进行类型转换并以这种方式访问成员。如果你不能保证这一点,这是危险的,可能会导致一些坏的错误


在本例中,要执行您想要的操作,请尝试System.out.printlnMazems.i

传递泛型类型时,继承仅对传递的最泛型类型的基本功能起作用。例如,在这种情况下,如果不是每个模型都有公共int;,如果不进行类型转换,您就无法直接访问它。我们稍后将对此进行讨论。此外,在这种特殊情况下,您只能访问模型类中显式定义的函数和变量,因为所有派生类都保证这些函数和变量相同

然而,现在,如果您确实知道您有一个给定类型的特定子类,那么您可以对其进行类型转换并以这种方式访问成员。如果你不能保证这一点,这是危险的,可能会导致一些坏的错误

在本例中,要执行您想要的操作,请尝试System.out.printlnMazems.i

它可能是一个迷宫,但也可能是模型的其他子类。这就是为什么你不能假装它确实是一个迷宫,并访问它的成员,因为它可能不是一个

如果您知道这是一个迷宫,那么为什么不声明SceneView构造函数来执行迷宫呢?如果你不能,你仍然可以铸造它:Maze ms.i,但这是一个臭代码。

它可能是一个迷宫,但也可能是模型的其他子类。这就是为什么你不能假装它确实是一个迷宫,并访问它的成员,因为它可能不是一个


如果您知道这是一个迷宫,那么为什么不声明SceneView构造函数来执行迷宫呢?如果不能,您仍然可以强制转换:Maze ms.i,但这是一个糟糕的代码。

不,问题是您传递了一个模型,但Maze是一个包含公共变量i的类。顺便说一句,这主意不好。你的理解有大问题

我想你想把我拉上模特班。那时一切都会好起来的


如果你通过一个迷宫,一切都会好起来,因为Liskov替换原理说迷宫是一个模型,所以你可以毫无问题地将它传递给SceneView。

不,问题是你通过了一个模型,但迷宫是一个具有公共变量i的类。顺便说一句,这主意不好。你的理解有大问题

我想你想把我拉上模特班。 那时一切都会好起来的


如果你进入一个迷宫,一切都会好起来,因为Liskov替换原理说迷宫是一个模型,所以你可以毫无问题地将它传递到SceneView。

即使它实际上是一个迷宫,但你将它声明为模型。编译器将检查模型的属性,因此您将收到一个编译器错误。你可以投射它,它会工作。

即使它实际上是一个迷宫,但你将它声明为一个模型。编译器将检查模型的属性,因此您将收到一个编译器错误。你可以投下它,它会起作用。

你总是可以通过

if(ms instanceof maze.class){
//recast back to maze
}

但它有点老套,通常不被接受。

你可以通过

if(ms instanceof maze.class){
//recast back to maze
}

但是它有点粗糙,通常不被接受。

如果您将参数i从类迷宫移动到类模型,它应该可以工作

如果将参数i从类迷宫移动到类模型,它应该可以工作

我认为您想要的是这样的东西,这取决于您是否能够定义模型。这假设i不是每个模型都会有的,否则将i向上移动到模型的建议要简单得多,并将其作为私有保护并使用getter

public abstract class Model { // or even interface
    public String modelAsString();  // possibly just use Object.toString()
}

public class Maze extends Model { // or implement, if Model is interface
    private int i;
    ...
    public String modelAsString() { return "i = " + i; }
}

public SceneView(Model ms) {
    this.ms = ms;
    System.out.println(m.modelAsString()); // Now any Model subtype will work

我认为您想要的是这样的东西,这取决于您是否能够定义模型。这假设i不是每个模型都会有的,否则将i向上移动到模型的建议要简单得多,并将其作为私有保护并使用getter

public abstract class Model { // or even interface
    public String modelAsString();  // possibly just use Object.toString()
}

public class Maze extends Model { // or implement, if Model is interface
    private int i;
    ...
    public String modelAsString() { return "i = " + i; }
}

public SceneView(Model ms) {
    this.ms = ms;
    System.out.println(m.modelAsString()); // Now any Model subtype will work

你有一个模型,而不是迷宫。该模型不包含名为iRahter-than-answer的公共字段,我将向您提出一个需要思考的问题:如果您尝试传递不同的模型子类而不是Maze,并且它没有定义字段I,您认为会发生什么?您好@Kevin,我计划稍后使用if语句来区分不同的子类。。。所以这是坏的OOP?是的,它不被认为是好的OOP,正如下面几个答案所示。有更好的方法来处理这个问题。谢谢@Kevin,你能给我一些提示或链接来帮助我更好地处理这个问题吗?我无法让子类执行我在视图类中要执行的操作,因为这将破坏MVC。您有一个模型,而不是迷宫。该模型不包含名为iRahter-than-answer的公共字段,我将向您提出一个需要思考的问题:如果您尝试传递不同的模型子类而不是Maze,并且它没有定义字段I,您认为会发生什么?您好@Kevin,我计划稍后使用if语句来区分不同的子类。。。所以这是坏的OOP?是的,它不被认为是好的OOP,正如下面几个答案所示。有更好的方法来处理这个问题。谢谢@Kevin,你能给我一些提示或链接来帮助我更好地处理这个问题吗?我无法让子类执行我在视图类中要执行的操作,因为这会破坏MVC。但如果我描述了迷宫特定的状态,它就没有理由出现在模型中。但如果我描述了迷宫特定的状态,它就没有理由出现在模型中。您可以强制转换它,但这通常是一个有缺陷的设计的标志。@QuantumMechanical你能解释一下为什么这样投是一个有缺陷的设计标志吗?我对OOP一无所知,但这对我来说很有意义,因为这样我的视图类就可以接受对所有类型模型类的引用。好的面向对象设计是如何实现的?这要看情况而定。若我是模型的所有子类都会使用的东西,那个么将它向上移动到模型中是有意义的。但是,如果我只是一个对迷宫有意义的东西,那么你就不应该这样做——因为如果你这样做了,你就基本上把只在一种特定类型的模型中有意义的东西放到了所有类型的模型中。这不是一个好的设计。你可以投下它,但这通常是一个有缺陷的设计的标志。@QuantumMechanical你能解释一下为什么投下这样的图案是一个有缺陷的设计的标志吗?我对OOP一无所知,但这对我来说很有意义,因为这样我的视图类就可以接受对所有类型模型类的引用。好的面向对象设计是如何实现的?这要看情况而定。若我是模型的所有子类都会使用的东西,那个么将它向上移动到模型中是有意义的。但是,如果我只是一个对迷宫有意义的东西,那么你就不应该这样做——因为如果你这样做了,你就基本上把只在一种特定类型的模型中有意义的东西放到了所有类型的模型中。这不是一个好的设计。请看我对安娜的评论。只有当我在模型的所有子类中都有意义时,将i拉到模型中才有意义。如果我是某个特定于迷宫的东西,你不想把它拉到基类,那么迷宫就不是模型。或者这种方法需要走迷宫。你的设计仍然是错误的。请看我对安娜的评论。只有当我在模型的所有子类中都有意义时,将i拉到模型中才有意义。如果我是某个迷宫特有的东西,y
你不想把它拉到基类上去,那么迷宫就不是模型了。或者这种方法需要走迷宫。你的设计仍然是错误的。嗨@QuantumMechanical,谢谢你。那么您是说,使用良好的OOP设计,任何特定于任何子类的内容都由类本身处理,而不是使用强制转换?但这肯定会打破我的MVC设计模式,因为我必须让我的迷宫类自己呈现在屏幕上,而它应该只做模型的工作?迷宫不需要自己呈现。它只需要提供适当的输入。但是,您正在考虑MVC中的适当职责,这是很好的。这很容易让人觉得马虎。嗨@QuantumMechanic,谢谢你。那么您是说,使用良好的OOP设计,任何特定于任何子类的内容都由类本身处理,而不是使用强制转换?但这肯定会打破我的MVC设计模式,因为我必须让我的迷宫类自己呈现在屏幕上,而它应该只做模型的工作?迷宫不需要自己呈现。它只需要提供适当的输入。但是,您正在考虑MVC中的适当职责,这是很好的。这很容易让人变得草率。嗨@akhisp,对不起,我还没有完全掌握Java术语。把它作为模型的一个成员,你的意思是将迷宫作为模型的一个内部类,还是作为一个独立类,并从模型中创建一个实例?他的意思是将变量“i”从迷宫移动到模型中。作为类成员的变量通常也被称为字段。或者实例变量。嗨@akhisp,对不起,我还没有完全掌握Java术语。把它作为模型的一个成员,你的意思是将迷宫作为模型的一个内部类,还是作为一个独立类,并从模型中创建一个实例?他的意思是将变量“i”从迷宫移动到模型中。作为类成员的变量通常也被称为字段。或者实例变量。cheers@Kevin,因此您建议使用方法将每个模型编码为可从基类访问的通用格式,例如编码为字符串?是的,在这种情况下,字符串的演示非常简单,但根据视图的需要,您可能需要更复杂的内容。cheers@Kevin,因此,您建议使用方法将每个模型编码为可从基类访问的通用格式,例如编码为字符串?是的,在本例中,字符串的演示非常简单,但您可能需要更复杂的内容,具体取决于视图的需要。