我对Android编程比较新(~2个月) 是否有必要为几十个不同的变量设置getter?
例如 -
JAXBElement<ParentOfSomeClass> elementParent = ...
name.add(elementParent); //Compile-error
虽然有必要为浮点数和字符串设置不同的getter和setter,但这是不好的做法,如果是这样,为什么要使用类似switch语句的东西来返回不同的变量呢?
//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;
}
那么,上面的代码被认为是坏的吗?如果是这样,请解释原因。
感谢您的帮助,这不是一个真正的问题,因为无论哪种方式都可以正常工作,我只是不明白为什么如果没有充分的理由,人们会使用几十个吸气剂和制定者。
我认为同样的问题适用于setter
答案 0 :(得分:9)
因为你做的事情就像
public float returnSomething(String theThing) {
switch (theThing) {
case "height":
return height;
case "rotation" :
return rotation;
case "width":
return width;
default:
return 0;
}
}
我可以感受到Stack Overflow的下一个问题,&#34;为什么我的身高总是0?&#34;
然后发布代码,如
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();
他们认为班级User
是这样的:
public class User {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
一个有趣的说明是,Realm创建了一个&#34;代理子类&#34;他们重新定义了setName
和getName
方法(也就是说,你需要getter / setter来使一些系统工作!他们假设你拥有它们!)
但重要的是,您需要使用"name"
提供字段名称。
稍后,任何人都可以输入错字,或者您只是不记得的字段。在这种特殊情况下,他们倾向于创建元模型(为您存储字段名称的东西),以便您赢得不必使用字符串引用字段名称。
例如,在Criteria 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));
因此,它消除了对String
的需求。
同样地,我倾向于使用Realm来创建一个&#34;元模型&#34; (尽管您现在可以使用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。) 不是类型安全的;你很幸运,无论你在这个例子中得到什么float
,但是当它可以是String
时,你需要返回Object
并投射它或使用{{1无论谁调用该方法,都必须确切地知道它们正在接收什么 - 也容易发生运行时错误。
答案 1 :(得分:3)
Getters&amp; Setters为您提供类型安全。但是,仅将它用于需要从类外部访问(获取/设置)的变量。您可以并且应该通过使用合适的构造函数来最小化它,在大多数情况下这是正确的方法,因为它通过消除背景中的神奇变化来提高代码的清晰度,这可能是多线程代码的一个严重的痛苦,但可以即使在编程不佳的常规代码中也存在很大问题。
仅仅因为你有二十个级别的私有变量并不意味着你必须创建getXXX()&amp;每个的setXXX()!
BTW:现在大多数IDE都像Eclipse一样可以为你自动生成它们。答案 2 :(得分:2)
只需在需要时创建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区域结束。为什么,注意拼写错误。如果你有单独的方法,那么编译器会在编译时说出来。
此外,如果您有许多变量,则需要进行大量检查。
答案 3 :(得分:2)
我也不是getter / setter的朋友,但他们可能是最好的解决方案。 IDE将为这些字段提供代码生成。
原因:坚如磐石,不易出错,以后更容易。
在真正需要时只制作吸气剂/定型剂。 public void move(float, float)
和其他更有趣的方法可能会将坐标计算大部分放在类本身内。
答案 4 :(得分:1)
您只需为需要使用或更新的变量声明getter和setter。
我认为这只是一种习惯,你的回报可以很好地工作,但是更容易打电话和理解:
class.getHeight()
大于
class.returnSomething("height")
答案 5 :(得分:1)
有趣的话题。我觉得还有第三个答案。有一个论点说Getters and Setters are evil,你应该避免使用它们。因为您基本上将成员声明为private
,但通过getter和setter授予公共修改权限。
让我们比较两者。这是一个使用getter和setter的人类
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;
}
}
使用此课程:
Person me = new Person();
me.setName("Ian");
me.setAge(24);
System.out.println("Name: " + me.getName());
System.out.println("Age: " + me.getAge());
现在让我们在不使用getter和setter的情况下创建相同的类。
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使用getter和setter。
反对在面向对象语言中使用getter和setter的整个论点可归纳为:
程序代码获取信息然后做出决定。面向对象 代码告诉对象做事。 - 亚历克夏普
作为一个简单的例子,假设我们想要将Person
的信息写入数据库。一些开发人员倾向于创建一个具有函数的数据库接口
void writeToPersons(Person person)
将使用getter和setter将所需数据写入数据库。
根据getter和setter nay的说法,Person
本身应负责自己编写数据库。
public class Person implements Storable {
public void writeToDatabase() {
}
}
要回答你的问题,我宁愿使用getter和setter而不是你的第二个建议,因为你最终会为每个属性添加一组常量或枚举。这需要在两个不同的地方进行代码维护,这只会增加另一个故障点。
答案 6 :(得分:1)
我同意之前的答案,但我会稍微概括一下。 returnSomething
方法的问题在于它将一些拼写检查从编译时转移到运行时。
非常灵活的代码有时间和地点,大多数检查都是在运行时完成的。在那些情况下,我不使用Java。
编译时间检查以及支持它们的语言的最大优点是它们相当于普遍量化的测试:“对于每个不使用反射的可编译程序,每个get请求都是有效的属性。”而不是“对于此测试套件中的所有测试用例,每个获取请求都是有效的属性”。