Java- getters 的最佳实践,单个 getter 或多个不同变量?

Java- Best practice for getters, single getter or multiple for different variables?

我对 Android 编程比较陌生(~ 2 个月) 几十个不同的变量需要getter吗?

例如 -

//Yes I realise that this isn't 'dozens'
public float getX() {
    return position.x;
}

public float getY() {
    return position.y;
}

public float getWidth() {
    return width;
}

public float getHeight() {
    return height;
}

public float getRotation() {
    return rotation;
}

例如,虽然有必要为浮点数和字符串设置不同的 getter 和 setter,但对 return 不同的变量使用类似 switch 语句之类的东西是不好的做法吗? ?

public float returnSomething(String theThing) {
    switch (theThing) {
        case "height":
            return height;
        case "rotation" :
            return  rotation;
        case "width":
            return  width;

        default:
            return 0;
    }
}

那么,上面的代码算是不好的吗?如果是,请说明原因。

感谢您的帮助,这不是真正的问题,因为任何一种方法都可以正常工作,我只是不明白为什么如果没有充分的理由人们会使用几十个 getter 和 setter。

我想同样的问题也适用于二传手

您只需为需要使用或更新的变量声明 getter 和 setter。

我认为这只是一种习惯,你的 returnSomething 可以正常工作,但更容易调用和理解:

class.getHeight()

class.returnSomething("height")

因为当你做类似

public float returnSomething(String theThing) {
    switch (theThing) {
        case "height":
            return height;
        case "rotation" :
            return  rotation;
        case "width":
            return  width;

        default:
            return 0;
    }
}

我能感觉到Stack Overflow的下一个问题,"Why is my height always 0?"

然后 post 代码如

public class GameThingy {
      //...

     private void doStuff(GameObject gameObject) {
         float gravity = 5*gameObject.returnSomething("hieght");
         gameObject.setSomething("velocyty", gravity+50);
     }
}

从技术上讲,只要您在任何地方打错字,您就会很难找到问题的根源。那,你很幸运,这些字段都是 float,它们不一定是。

编辑: 顺便说一句,这实际上是一些数据库查询中定义感兴趣字段的典型问题。就像,必须通过 String 指定您要查找的字段。

现实生活中的例子是 RealmQuery<T>

一个 RealmQuery<T> 看起来像这样:

RealmQuery<User> query = realm.where(User.class);

// Add query conditions:
query.equalTo("name", "John");

// Execute the query:
RealmResults<User> result1 = query.findAll();

他们认为 class User 是这样的:

public class User {
    private String name;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

一个有趣的注意事项是 Realm 创建了一个 "proxy subclass",他们在其中重新定义了 setNamegetName 方法(也就是说,您需要 getters/setters 才能使某些系统正常工作!他们假设你拥有它们!)

但是这里重要的是你需要提供字段名称 "name".

稍后,任何人都可能会打错字,否则您只是记不住这些字段。在这种特殊情况下,他们倾向于创建一个 元模型 (为您存储字段名称的东西),目的是您 不必使用字符串 引用字段名称。

例如,在标准 API 中,而不是

Root<Pet> pet = cq.from(Pet.class);
cq.select(pet.get("name"));

他们有这样的元模型:

Root<Pet> pet = cq.from(Pet.class);
cq.select(pet.get(Pet_.name));

因此,它消除了 Strings 的需要。

同样,我倾向于使用 Realm 来创建一个 "metamodel"(尽管您现在可以使用 RealmFieldNamesHelper 自动为您生成它):

public class User
        extends RealmObject {
    @PrimaryKey
    private long id;
    private String name;

    public static enum Fields { //this is the "metamodel"
        ID("id"),
        NAME("name");

        private String fieldName;

        Fields(String fieldName) {
            this.fieldName = fieldName;
        }

        public String getField() {
            return fieldName;
        }

        @Override
        public String toString() {
            return getField();
        }
    }
}

因此您可以像这样替换查询

RealmResults<User> result2 = realm.where(User.class)
                                  .equalTo(User.Fields.NAME.getField(), "John")
                                  .or()
                                  .equalTo(User.Fields.NAME.getField(), "Peter")
                                  .findAll();

但是有了 getter 和 setter,您已经拥有了类型安全,并且您已经拥有了您不必记住的方法 - 因此,您拥有了编译时错误检查。

所以回答你的问题,在 Java 中通过字符串名称引用变量是一种不好的做法的原因是因为

1.)可能会出现错别字,错误只会出现在运行时,而不是编译时

2.) 类型不安全;你很幸运,无论在这个例子中是什么,你都能得到 floats ,但是当它可以是 String 时,你需要 return Object 并施放它或者使用 public <T> T get(String field) { ... } 并且调用该方法的任何人都必须确切地知道他们正在接收什么 - 也容易出现运行时错误。

只需在需要时创建 getter 和 setter。

public float returnSomething(String theThing) {
    switch (theThing) {
        case "height":
            return height;
        case "rotation" :
            return  rotation;
        case "width":
            return  width;

        default:
            return 0;
    }
}

如果你尝试做 area = returnSomething("width") * returnSomething("heigth") 你将总是以 0 区域结束。为什么,注意拼写错误。如果你有单独的方法,那么编译器会在编译时说出来。

此外,如果你有很多变量,你需要做很多检查。

Getters & Setters 为您提供类型安全。但是,仅将它用于需要从 class 外部访问 (get/set) 的变量。你可以而且应该通过使用合适的构造函数来最小化它,在大多数情况下这是正确的方法,因为它通过消除后台的神奇变化来增加代码的清晰度,这对于多线程代码来说可能是一个严重的痛苦但可以即使在编程不佳的常规代码中也是一个大问题。

仅仅因为您有二十个 class 级私有变量并不意味着您必须为每个变量创建 getXXX() 和 setXXX()!

顺便说一句:如今大多数 IDE 像 Eclipse 一样可以自动为您生成它们。

我也不是 getters/setters 的朋友,但他们可能是这里最好的解决方案。 IDE 将为此类字段提供代码生成。

原因:坚如磐石,不易出错,便于后期修改。

只有在真正需要的时候才getters/setters。 public void move(float, float) 和其他更有趣的方法可能会将坐标计算主要放在 class 本身内。

有趣的话题。我觉得还有第三个答案。有一个论点说 Getters and Setters are evil,你应该完全避免使用它们。因为您实质上是将成员声明为 private,但通过 getters 和 setters 授予 public 修改权限。

让我们比较一下两者。这是一个人 class 使用 getters 和 setters

public class Person {
    private String name;
    private int age;

    public String getName() {
        return this.name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return this.age;
    }

    public void setAge(int name) {
        this.age = age;
    }
}

使用这个 class:

Person me = new Person();
me.setName("Ian");
me.setAge(24);

System.out.println("Name: " + me.getName());
System.out.println("Age: " + me.getAge());

现在让我们在不使用 getter 和 setter 的情况下创建相同的 class。

public class Person {
    public String name;
    public int age;
}

访问权限为:

Person me = new Person();
me.name = "Ian";
me.age = 24;

System.out.println("Name: " + me.name);
System.out.println("Age: " + me.age);

如您所见,getter 和 setter 模式增加了相当多的额外输入。然而,有大量 advantages 使用 getters 和 setters。

反对在面向对象语言中使用 getter 和 setter 的整个论点可以概括为:

Procedural code gets information then makes decisions. Object-oriented code tells objects to do things. — Alec Sharp

举个简单的例子,假设我们要将Person的信息写入数据库。一些开发人员倾向于创建一个具有函数

的数据库接口
void writeToPersons(Person person)

将使用 getters 和 setters 将所需数据写入数据库。

根据 getter 和 setter 反对者的说法,Person 本身应该负责自己编写数据库。

public class Person implements Storable {

    public void writeToDatabase() {

    }
}

为了回答你的问题,我宁愿使用 getters 和 setters 而不是你的第二个建议,因为你最终会为每个 属性 添加一组常量或枚举.这需要在两个不同的地方进行代码维护,这只会增加另一个故障点。

我同意前面的回答,但我要概括一下。 returnSomething 方法的问题在于它将一些拼写检查从编译时转移到 运行 时。

对于非常灵活的代码,在某些时间和地点,大多数检查都是在 运行 时完成的。在那些情况下,我不使用 Java.

编译时检查以及支持它们的语言的最大优势在于,它们执行的是等价于普遍量化的测试:"For every compilable program that does not use reflection, every get request is for a valid attribute." 而不是 "For all the test cases in this test suite, every get request is for a valid attribute"。