在其他 类 JAVA 中使用构造函数、方法、数据成员的最有效方式

Most efficient way of using constructors, methods, data members in other classes JAVA

网上找不到相关的解释 我有作业要做我应该创建一个名为 Shapes 的 class 和另外 2 个 classes,一个用于矩形,第二个用于圆形。 我想知道安排构造函数、数据成员和方法的最佳方式是什么,因为例如对于矩形,我应该有高度和宽度,而圆有半径。

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

在矩形 class 中看起来像这样:

public Rectangle() {
    super();
}

public Rectangle(int x, int y, int width, int height, String color) {
    super(x, y, width, height, color);
}

在圈子里class我是这样做的:

public Circle() {
    super();
}

public Circle(int x, int y, String color, double radius) {
    super(x, y, color, radius);
}

我需要一种打印方法来打印每个 class 中与 class 相关的所有信息 有没有办法在基础(形状)class 中使用这种打印方法避免使用多种打印方法?

有不同的参数要显示,但我们被告知要避免代码相乘。

一个基 class 永远不应该有任何不是其所有子 class 共有的属性。事实上,它甚至不应该知道它的 subclasses。有关详细信息,请阅读 里氏替换原则Open/Closed 原则

因此基数 class 可能只有参数 xycolor。所以 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;
}

你重载基础 class 构造函数以适应不同的派生 classes 的方式确实是一个非常糟糕的设计。它不仅与上述原则相矛盾。对于阅读代码的人来说也很难理解。

只有当成员对所有子class 都有意义时,才将它们放在超级 class 中。您还应该使用抽象 class 来防止创建普通的 Shape 对象,并使用 protected 关键字来向外界隐藏成员,但允许子 classes 查看它们。

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
}

让我们从属性开始。您应该考虑一个属性是适用于 class 的子 class 还是仅适用于其中的一部分。例如,在 Shapes class 中放置一个 "radius" 属性是否有意义? Shape 的所有子 class 都需要该属性吗?想想矩形:矩形(实例)有半径吗?如果在 Shapes 中声明 radius 属性,矩形实例的值是多少?避免在 classes 中使用备用属性,以提高性能但主要是为了提高可读性。这同样适用于宽度和高度。

现在,颜色呢?每个形状都有颜色吗?那么,它是一个共享属性吗?

这里的 x 和 y 属性有些特殊:同一个属性可能意味着两个完全不同的东西:对于圆应该是圆心,但是对于矩形可能是左上角(或其他)点.它们应该是相同的属性,还是应该是两个不同的属性对?我会选择第二个,但这是我的意见。

最后,关于构造函数:你会让别人创建一个既不是圆形也不是矩形的形状实例吗? Shapes class 中是否需要 public 构造函数?是否感觉到形状只是一个形状而不是圆形或矩形(或形状的任何其他子class)?

顺便说一句:我认为最好将您的 Shapes class 重命名为 Shape.. class 代表一个概念;然后您可以创建该概念的实例,这些实例是形状...

=== 编辑 ===

我忘记了你关于打印方法的问题的最后一部分:你决定把每个属性放在哪里,你会自己找到并回答.. class 的方法可以访问某些属性中的属性吗他们的子classes?

哦,还有一点:toString 方法总是存在的,因为它是在对象中定义的 class.. 考虑一下 toString 方法和您需要的 print 方法的关系。

使用一种抽象方法使形状 class 成为抽象的 class,所有其他 classes 都必须定义该方法

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

这只是我的意见。有许多其他方法可以构建这些 classes,但这完全取决于您要如何使用它们。我提供的方法可以很容易地将其扩展到 3D,因此您可以像这样声明 3D 形状基础 class:

public abstract class Shape3D extends Shape {
    protected int z;

    public Shape3D() {
        super();
    }
}

并不是说您需要 3D 对象,而是随着项目变得越来越复杂,不要让自己陷入设计之中。


在你的主 class 中,你可以有一个 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());
        }
    }
}

最后一记;当您发现自己必须为 class 编写很长的构造函数时,您可能想问问自己是否会从使用构建器模式中获益。例如,矩形 class 可以使用如下构建器创建:

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