无法在线查找相关说明 我有功课要做我应该创建一个名为Shapes的类,另外两个类用于矩形,第二个用于圆形。 我想知道排列构造函数,数据成员和方法的最佳方法是什么,因为例如对于矩形,我应该有高度和宽度,圆圈有半径。
public class Shapes {
//Should I use only common Data members, constructors and functions in the base class?
private int x;
private int y;
private int width;
private int height;
private String color;
private double radius;
我如何使用super()创建相关的构造函数? 我想我把它弄得一团糟:
//Constructors:
public Shapes() {
}
//Common constructor
public Shapes(int x, int y, String color) {
setX(x);
setY(y);
setColor(color);
}
//Circle constructor:
public Shapes(int x, int y, String color, double radius) {
this(x, y, color);
setRadius(radius);
}
//Rectangle constructor:
public Shapes(int x, int y, int width, int height, String color) {
this(x, y, color);
setWidth(width);
setHeight(height);
}
矩形类中的看起来像这样:
public Rectangle() {
super();
}
public Rectangle(int x, int y, int width, int height, String color) {
super(x, y, width, height, color);
}
在圆圈课中,我这样做了:
public Circle() {
super();
}
public Circle(int x, int y, String color, double radius) {
super(x, y, color, radius);
}
我需要一个print方法来打印与类相关的每个类的所有信息有没有办法在base(shapes)类中使用这个print方法来避免多种打印方法?
要显示不同的参数,但我们已被告知要避免代码的倍增。
答案 0 :(得分:1)
基类不应该具有任何不属于其所有子类的属性。事实上,它甚至不应该知道它的子类。有关更多信息,请阅读 Liskov替换原则和开放/封闭原则。
因此,基类应该只有参数x
,y
和color
。所以Shapes
构造函数可能是这样的:
public Shapes(int x, int y, String color) {
setX(x);
setY(y);
setColor(color);
}
和Circle构造函数如下:
public Circle(int x, int y, String color, double radius) {
super(x, y, color);
this.radius = radius;
}
重载基类构造函数以适应不同派生类的方式实际上是一个非常糟糕的设计。它不仅违背了上述原则。对于阅读代码的人来说,这也很难理解。
答案 1 :(得分:0)
如果成员对所有子类都有意义,则只将成员放在超类中。您还应该使用抽象类来阻止创建普通Shape
对象,并使用protected
关键字来隐藏外部世界的成员,但允许子类查看它们。
public abstract class Shape {
protected int x;
protected int y;
protected String color;
protected Shape() { this(0, 0, ""); }
protected Shape(int x, int y, String color) {
this.x = x;
this.y = y;
this.color = color;
}
// setter and getters for x, y, and color
}
public class Rectangle extends Shape {
private int width;
private int height;
public Rectangle() { this(0, 0, "", 0, 0); }
public Rectangle(int x, int y, String color, int width, int height) {
super(x, y, color);
this.width = width;
this.height = height;
}
// setters and getters for width and height
}
public class Circle extends Shape {
private double radius;
public Circle() { this(0, 0, "", 0.0); }
public Circle(int x, int y, String color, double radius) {
super(x, y, color);
this.radius = radius;
}
// setter and getter for radius
}
答案 2 :(得分:0)
让我们从属性开始。您应该考虑属性是否适用于类的子类,还是仅适用于某些类的子类。例如,在Shapes类中放置“radius”属性是否有意义? Shape的所有子类都需要该属性吗?想想矩形:矩形(实例)是否有半径?如果在Shapes中声明radius属性,那么矩形实例的值是什么?为了提高性能,避免在课堂上有备用属性,但主要是为了提高可读性。这同样适用于宽度和高度。
现在,颜色怎么样?每个形状都会有颜色吗?那么,它是一个共享属性?
x和y属性在这里有一些特殊之处:相同的属性可能意味着两个完全不同的东西:圆形应该是中心,但矩形可以是左上角(或任何其他)。它们应该是相同的属性,还是应该是两对不同的属性?我会选择第二个,但这是我的观点。
最后,关于构造函数:您是否可以让某人创建一个形状实例而不是圆形或矩形?你需要在Shapes类中使用公共构造函数吗?是否感觉形状只是一个形状而不是圆形或矩形(或任何其他形状的子类)?
顺便说一句:我认为最好将Shapes类重命名为Shape ..一个类代表一个概念;那么你可以创建那个概念的实例,它们是形状......
===编辑===
我忘记了关于打印方法的问题的最后一部分:你决定在哪里放置每个属性,你会找到并自己回答..类的方法可以在一些子类中访问属性吗?
哦,还有别的东西:toString方法总是存在,因为它是在Object类中定义的。考虑一下toString方法和你需要的print方法的关系。
答案 3 :(得分:0)
使用一个抽象方法使形状类成为一个抽象类,所有其他类都必须定义
public abstract class Shape {
protected int x;
protected int y;
protected String color;
public Shape(String color) {
this.color = color;
}
public Shape() {
this("0xfffffff");
}
public Shape(int x, int y, String color) {
this(color);
this.x = x;
this.y = y;
}
public Shape(int x, int y) {
this();
this.x = x;
this.y = y;
}
public int getX() { return x; }
public int getY() { return y; }
public String getColor() { return color; }
public void setX(int x) { this.x = x; }
public void setY(int y) { this.y = y; }
public void setColor(String color) { this.color = color; }
@Override
public abstract String toString();
}
public class Rectangle extends Shape {
private int width;
private int height;
public Rectangle(int width, int height){
super();
this.width = width;
this.height = height;
}
public Rectangle(int width, int height, String color){
super(color);
this.width = width;
this.height = height;
}
public int getWidth() { return width; }
public int getHeight() { return height; }
// Also include setters if you don't need immutability
@Override
public String toString() {
return String.format("Rectangle\nWidth: %d\nHeight: %d\nColor: %s", width, height, color);
}
}
这只是我的意见。构建这些类有许多其他方法,但这一切都取决于您希望如何使用它们。我提供的方式可以很容易地将其扩展为3D,因此您可以像这样声明3D Shape基类:
public abstract class Shape3D extends Shape {
protected int z;
public Shape3D() {
super();
}
}
并不是说你需要一个3D对象,但是所有这些都是因为项目变得越来越复杂,所以不会陷入设计之中。
在您的主课程中,您可以拥有一个Shape
数组,并且您可以轻松打印它们,因为它们都已经定义了toString
方法。
public final class Main {
public static void main(String []args) {
List<Shape> shapes = new ArrayList<>();
// fill the list with all kinds of shapes
for (Shape shape: shapes) {
System.out.println(shape); // Will default to System.out.println(shape.toString());
}
}
}
最后要注意的是;当您发现自己必须为一个类编写长构造函数时,您可能想问自己是否可以从使用Builder模式中受益。例如,可以使用以下构建器创建Rectangle类:
public abstract class ShapeBuilder {
int x, y;
String color;
public ShapeBuilder setX(int x) {
this.x = x;
return this;
}
public ShapeBuilder setY(int y) {
this.y = y;
return this;
}
public ShapeBuilder setColor(String color) {
this.color = color;
return this;
}
public abstract <T extends Shape> T build();
}
public class RectangleBuilder extends ShapeBuilder {
int width;
int height;
public RectangleBuilder setWidth(int width) {
this.width = width;
return this;
}
...
@Override
public Rectangle build() {
Rectangle rect = new Rectangle(width, height, color);
rect.setX(x);
rect.setY(y);
return rect;
}
}