最佳实践:随着时间的推移填充实例变量

时间:2015-04-20 10:16:45

标签: java oop class-design design-principles

我是面向对象编程概念的新手(在java中),我经常遇到以下设计问题:

我经常使用实例变量创建类,这些实例变量在初始化时是未知的。随着时间的推移填充这些变量。这不是一个真正的问题,因为这些变量在填充之前是空的,因此我的问题更多地是关于这种情况下的最佳实践。

让我用一个例子解释一下。我有一个班级Car。每个Car都有colorvMaxweighthorsepower等。

初始化Car时,只有colorweighthorsepower已知。 - > Car(color, weight, horsepower)

现在可以计算vMax(例如:weight/horsepower)。让我感到困惑的是,初始化后的Car是“不完整”,这意味着vMax只会随着时间的推移而填充。

我觉得这很难看,当然汽车的例子很简单。我经常会有10多个属性的类,其中一些是随着时间的推移计算出来的,后者在代码中后来用于计算该对象的更多属性。然后很难知道哪些变量已经在某一点被填充,哪些变量没有被填充。

我只是想知道这是否“正常”以及OOP的工作方式,或者是否应该避免这种情况。如果是的话,我会很高兴看到一些设计提示。

迈克尔

7 个答案:

答案 0 :(得分:2)

正如您定义的vMax应该比method更多属于该类的属性:

class Car {
    private String color;
    private double weight;
    private double horsePower;

    // constructor for Car
    public Car (String color, double weight, double horsePower) {
        this.color = color;
        this.weight= weight;
        this.horsePower= horsePower;
    }

    // usually I would create this as one-line-method...  but to clarify:
    public double getVMax() {
        double vMax = weight / horsePower; // calculate vMax!!!
        return vMax;
    }
}

答案 1 :(得分:1)

这完全取决于你需要什么。

我想到的第一件事就是使用构建器(特别考虑到你提到的#34;具有10多个属性的类")

构建器的主要思想是,在知道/计算其所有属性之前,不要创建对象。

让我们回到你的汽车示例。

class Car
{
    final int weight;
    final int horsepower;
    final int vMax;
    final String color;

    private Car(int weight, int horsepower, int vMax, String color)
    {
        this.weight = assetNotNull(weight);
        this.horsepower = assetNotNull(horsepower);
        this.vMax = assetNotNull(vMax);
        this.color = assetNotNull(color);
    }

    //..... other car-related methods

    /** Car builder */
    public static class Builder
    {
        int weight;
        int horsepower;
        int vMax;
        String color;

        public Builder setWeight(int weight)
        {
            this.weight = weight;
            return this;
        }

        public Builder setHorsepower(int horsepower)
        {
            this.horsepower = horsepower;
            return this;
        }

        public Builder setvMax(int vMax)
        {
            this.vMax = vMax;
            return this;
        }

        public Builder setColor(String color)
        {
            this.color = color;
            return this;
        }

        public Car createCar()
        {
            return new Car(weight, horsepower, vMax, color)
        }
    }
}

然后你可以像这样建造你的车

Car.Builder builder = new Car.Builder();
Car car = builder.setColor("blue")
            .setHorsepower(10)
            .setvMax(100)
            .setWeight(1000)
            .createCar();

这种方法有以下好处:

  • 在设置所有必填字段时构建Car对象。如果您需要额外的 验证,您可以将其添加到createCar()方法
  • 您可以在不同方法之间传递Builder对象以填充字段。
  • 每当你有一个Car对象时,你就相信它是有效的(它不可能 另外实例化)
  • 您的Car对象是线程安全的:)

希望有所帮助。

答案 2 :(得分:0)

听起来你可以在构造函数中设置vMax作为参数权重和马力传递给它。

答案 3 :(得分:0)

如果您正在处理越来越多的属性,我建议您使用Properties design pattern and prototype based Java Programming。否则,我会设计如下,在构造函数本身中计算vMax,这样每次访问时都不需要验证null

class Car {
    private String color;
    private double weight;
    private double horsePower;

    Car(String color, double weight, double horsePower){
     // other fields
     calculateVMax();
    }

    private void calculateVMax() {
        double vMax = weight/horsepower;
        setVMax(vMax); // initialize vMax
    }
    // setters and getters for vMax, color, weight and horse power
}

如果不是一次,那么可能采用单独的方法是最好的方法。大多数情况下,getVMax将始终尝试计算vMax,如下所述。

public double getVMax(){
  return (double) (weight/horsePower);
}

答案 4 :(得分:0)

您只需在构造函数中计算vMax值,如下所示:

class Car {
    private String color;
    private double weight;
    private double horsePower;
    private double vMax;

    public Car(){
       super();
    }

    public Car(String color, double weight, double horsePower){
       this.color = color;
       this.weight = weight;
       this.horsePower = horsePower;
       if(horsePower!=0) {
          this.vMax = weight / horsePower;
       } else {
          this.vMax = 0;
       }
    }

    // setters and getters 
}

并确保检查horsePower值不为零。

答案 5 :(得分:0)

继Maks Builder后,更流利......:

import org.apache.commons.lang3.Validate;

class Car {
    private String color;
    private double weight;
    private double horsePower;
    private double vMax;

    // setters and getters

    public String getColor() {
        return color;
    }

    public double getWeight() {
        return weight;
    }

    public double getHorsePower() {
        return horsePower;
    }

    public double getvMax() {
        return vMax;
    }   

    private void validate() {
        Validate.isTrue(!StringUtils.isBlank(color), "color may not be blank");
        Validate.isTrue(weight > 0L, "weight should be set");
        Validate.isTrue(horsePower > 0L, "horsePower should be set");

        if(horsePower!=0) {
            this.vMax = weight / horsePower;
         } else {
            this.vMax=0;
         }        
    }

    private Car(Builder builder) {
        this.color = builder.color;
        this.weight = builder.weight;
        this.horsePower = builder.horsePower;           
    }

    public static class Builder {

        private String color;
        private double weight;
        private double horsePower;

        public Builder withColor(String color) {
            this.color = color;
            return this;
        }

        public Builder withWeight(double weight) {
            this.weight = weight;
            return this;
        }

        public Builder withHorsePower(double horsePower) {
            this.horsePower = horsePower;
            return this;
        }             

        public Car build() {
            Car newCar = new Car(this);
            newCar.validate();
            return newCar;
        }

    }

}

然后简单地说:

Car car = new Car.Builder()
            .withColor("blue")
            .withHorsepower(10)
            .setWeight(1000)
            .build();

如果您正在使用eclipse,请参阅Bob the Builder: https://code.google.com/a/eclipselabs.org/p/bob-the-builder/

请注意,我已将validate方法移至Car类,因为我相信这会使一个更安全的版本。 Bob将在Builder上生成它。

答案 6 :(得分:0)

构建器模式适合这种情况但是因为你说的是​​OOP,所以在以后的时间点在类中添加更多属性是完全正常的。在需要的时候。比如像vMax=weight/horsepower这样的属性你可以写一个方法&通过getter方法使vMax可用于类外部的代码。

public void setVMax(int weight, int horsepower){
vMax=weight/horsepower;
}

您最初可以通过在构造函数中初始化它们来创建具有某些必需属性的类对象。

public Car (String color, double weight, double horsePower) {
        this.color = color;
        this.weight= weight;
        this.horsePower= horsePower;
    }

您可以编写重载的构造函数,但构建器模式将是一个更清晰的解决方案。太多重载的构造函数看起来不太好。

重载的构造函数表示您希望car length属性在以后的某个时间点创建对象

public Car (String color, double weight, double horsePower, int length) {
        this.color = color;
        this.weight= weight;
        this.horsePower= horsePower;
        this.length=length;
        }

在客户端类中根据您的要求创建对象

new Car("Red", 56.78, 789);
new Car("Blue", 67.98, 567, 45);