What are the alternatives to public fields?

2020-07-03 07:07发布

I am programming a game in java, and as the question title suggestions i am using public fields in my classes. (for the time being)

From what i have seen public fields are bad and i have some understanding why. (but if someone could clarify why you should not use them, that would be appreciated)

The thing is that also from what i have seen, (and it seems logical) is that using private fields, but using getters and setters to access them is also not good as it defeats the point of using private fields in the first place.

So, my question is, what are the alternatives? or do i really have to use private fields with getters and setters?

For reference here is one of my classes, and some of its methods.

I will elaborate more if needs be.

public double health;
//The player's fields.
public String name;
public double goldCount;
public double maxWeight;
public double currentWeight;
public double maxBackPckSlts;
public double usedBackPckSlts; // The current back pack slots in use
public double maxHealth; // Maximum amount of health
public ArrayList<String> backPack = new ArrayList<String>();

//This method happens when ever the player dynamically takes damage(i.e. when it is not scripted for the player to take damage.
//Parameters will be added to make it dynamic so the player can take any spread of damage.
public void beDamaged(double damage)
{
    this.health -= damage;
    if (this.health < 0)
    {
        this.health = 0;
    }
}

EDIT: For checking purposes, this is what my Weapon class looks like now: (Code sample is not working for some reason, so it does not look right.)

private final double DAMAGE;
private final double SPEED;

public Weapon(double initialDmg,double initialSpd,String startName,double initialWg)
{
    DAMAGE = initialDmg;
    SPEED = initialSpd;
    setItemName(startName);
    setItemWeight(initialWg);
}

public double getSpeed() 
{
    return SPEED;
}


public double getDamage()
{
    return DAMAGE;
}

As you can see, as the Weapon's DAMAGE and SPEED do not need to be changed, they can be final's for the time being. (if, later in the game, i decided these values can be "Upgraded" so to speak, i may add setters then , with validation, or just make a new weapon with the upgraded values) They get set in the Weapon's constructor.

Conclusion: getters and setters are fine, as long as they are used smartly, and only used when needed. (however)

12条回答
等我变得足够好
2楼-- · 2020-07-03 07:47

One advantage not yet mentioned for avoiding public fields: if there aren't any public fields, one may define an interface that includes all the public features of the class, have the class implement that interface, and then have everyplace that uses the class use the interface instead. If that is done, one may later design a class which has completely different methods and fields, but which implements the same interface, and use that class interchangeably with the original. If this is done, it may be useful to have the class implement a static factory method in addition to the constructor, and have the factory return an object of the interface type. Doing that would allow later versions of the factory to return an object of some other type. For example, one may come up with a low-cost version of the object in which many properties return constants; the factory could see if such an object would be suitable, and if so return one instead of the normal object.

Incidentally, the concept of using a mixture of constant and mutable objects in an adventure goes back at least to 1980. In Warren Robinett's "Adventure" cartridge for the 2600, each object has a number of pointers stored in ROM for things like position and state, so objects which aren't going to move (such as the castle gates or the "signature") don't need to have their position stored in RAM, and most grabbable objects (which don't have any state other than their position) won't need to store a state in RAM, but animated objects like the dragons and bat can store both state and position in RAM. On a machine with 128 bytes of RAM total, such savings were critical.

查看更多
劫难
3楼-- · 2020-07-03 07:53

If you have a private field with a method get() and a method set() that don't do anything other than retrieve and assign the value, you should just make the field public, as the field isn't really private, and the getters and setters only hurt performance. If the getters and setters check the value being set or if the value is allowed to retrieve, then go ahead and use getters and setters. e.g. If you have a variable private int width; and someone tries to put in -1 with a setter, and the setter makes sure it isn't negative, then that is a good use. For example:

private int width;
public int get(){
    return width;
}
public void set(int w){
    if (w < 0) throw new RuntimeException();
    else width = w;
}

This would be a good use of getters and setters. Otherwise, they hurt your performance if the only thing they do is assign or get the value without anything else.

So to make a long story short:

Use getters and setters when doing anything other than retrieving or assigning a value. Else, just use public fields.

i.e.

BAD:

private int width;
public int get(){
    return width;
}
public void set(int w){
    width = w;
}

GOOD:

private int width;
public int get(){
    return width;
}
public void set(int w){
    if (w < 0) throw new RuntimeException();
    else width = w;
}

GOOD if you don't want anything other than getting or setting:

public int width;
查看更多
Anthone
4楼-- · 2020-07-03 08:00

In Java, using private fields with getters/setters is the recommend practice, provided external clients of your class really need access to those fields.

Otherwise keep them as private fields and simply don't provide a getter/setter.

There are various reasons why this is a best practice:

  1. If clients are using your field directly and later something needs to change regarding that, you're stuck. With a getter you can do a whole lot of things before the field is accessed.
  2. There is something called the JavaBeans specification that requires you to use getter/setters. Without them your class (then called bean) won't interoperate with that. JSP and JSF's EL is one example of something that required your class to comply with JavaBeans standards.

(p.s. unrelated to your question, but you'd better not declare backPack as an ArrayList. Declare as List; code to interface, not to implementation)

查看更多
放我归山
5楼-- · 2020-07-03 08:02

A shorter version of your methods...

public void beDamaged(double damage) {
    health = Math.max(0, health-damage);
}

public void gainHealth(double gainedHp) {
    health = Math.min(maxHealth, health + gainedHp);
}

or even the following which can be called with +1 to gain, -1 to lose 1 hp.

public void adjustHealth(double adjustHp) {
    health = Math.max(0, Math.min(maxHealth, health + adjustHp));
}
查看更多
ら.Afraid
6楼-- · 2020-07-03 08:07

An advantage of using getters and especially setters is, that it is much easier to debug write access to the fields.

查看更多
SAY GOODBYE
7楼-- · 2020-07-03 08:07

Getters and setters are part of the public interface of your class. It's a contract between the class designer/developer and the users of that class. When you define getters and setters, you should be committed to maintain them in future versions.

Attributes should only correspond the implementation of a given version of the class. In this way, the class developer may unilaterally change the implementation, hence the field, without breaking his/her commitment to maintain the interfaces.

Here is an example. Consider a class called Point. If you decide that a Point has x and y public attributes, then you may never change this. In contrast, if you have get/set X/Y methods, subsequent versions of the class may use various internal representations: rectangular coordinates (x, y), but also polar (r, theta), etc. All this without modifying the public interface.

查看更多
登录 后发表回答