面向对象编程私有类字段+ get / set或公共类字段?

时间:2015-02-16 16:39:54

标签: java oop private public

我是一名初级开发人员(目前正在使用Java),我有一个关于代码正确性的问题,这是一个例子: 我正在Java上编写一个简单的MMO游戏表示,我有2个类(Character和spell)。 Character具有属性(mName,mHealth和mEnergy),Spell类具有属性(mSpellName,mSpellCost,mSpellDamage)。而Spell类也有一个名为execute的方法,这里是一个代码

public void spellExecute(Character caster, Character target) {
caster.mEnergy -= this.spellCost;
target.mHealth -= this.spellDamage
}

这种结构意味着Character字段是公共的,可以直接访问,在一些例子中,我看到所有字段必须是私有的,只能通过get / set方法访问。我的问题是:一般来说,哪种方式更正确?这对我来说很重要,因为我想写一个好的代码:)

6 个答案:

答案 0 :(得分:2)

通常,您将使用get / set方法,因为它们允许类通过这些方法来控制访问

使用您的课程的任何其他课程,只能以您描述的方式访问和更改您的字段。

例如,让我们看一个简单的(过度简化的)燃油泵

class Pump
{
    constant int PRICE_PER_LITRE = 100; //in pence

    private int litresDispensed;
    private bool nozzleUp;
    private int litresAvailable;
    private int price; //in pence

    construct()
    {
        litresDispensed = 0;
        nozzleUp = false;
    }

    startFuelling()
    {
        nozzleUp = true;
    }

    stopFuelling()
    {
        nozzleUp = false;
    }

    takeFuel(int litresTaken)
    {
        if(nozzleUp = true)
        {
            litresAvailable -= litresTaken;
            price += litresTaken * PRICE_PER_LITRE;
        }
        else
        {
            error("You must lift the nozzle before taking fuel!");
        }
    }

    getPrice()
    {
        if(nozzleUp = true)
        {
            error("You can't pay until you've finished fuelling! Please return the nozzle");
        }
        else
        {
            return price;
        }
    }
}

我们的最终获取方法非常重要,以确保在该人尝试付款之前完成剩余的交易。

如果我们允许直接获取价格,他们可以在他们完成燃料之前做到这一点!这会让他们偷走我们所有的燃料。

如图所示,get方法保护字段免受外部影响。它仍然可以被操纵,但以我们想要允许它被操纵的方式。另请注意,此字段根本没有设置方法:我们不希望用户能够设置自己的价格,只需我们指定的价格!

如果您编写只返回并设置字段的get / set方法,而不进行任何验证或检查,那么您可以简单地将该字段设为公开(或者,您需要决定是否应该直接访问该字段):那就是说,最好在可能的情况下使用get / set方法,因为它允许你在将来添加验证而不会破坏代码。

答案 1 :(得分:1)

Getter / setter更好,因为它封装或隐藏了实际类正在做的设置数据。将构造函数设置为private并让它初始化默认值,然后用户可以调用set方法来设置变量。

答案 2 :(得分:1)

Getter和setter(Java bean)更好。它还提供Encapsulation功能。这对隐藏数据很有用。

  private int id;

    public int getId() {
            return id;
    }

    public void setId(int id) {
           this.id = id;
    }

构造函数用于在创建对象时初始化值。但是如果要在创建对象后设置数据值,则必须调用setter行为而不是调用构造函数。

答案 3 :(得分:1)

具有私有字段的getter和setter通常遵循设计选择。原因是,您可以使用API​​保护变量免受来自客户端的无意更改。 请考虑以下示例

public class Dummy{
 public int age;
}

现在客户可以这样做

new Dummy().age = -1

使用setter和getter

public class Dummy{
   private int age;
   public void setAge(int age){
      if (age < 0){
       throw new RuntimeException("you are not allowed to do this");
   }
   ......
}

许多框架,例如Hibernate,IBATIS等。遵循这些命名约定。希望这能回答你的问题。

答案 4 :(得分:0)

首选吸毒者和制定者 - 毕竟,如果您不打算使用其主要功能,为什么要使用面向对象的语言?

在这种情况下使用setter,您可以轻松地实施健全性规则,而无需每个调用者必须复制逻辑,例如 - 在角色尝试:

public void reduceMentalHealth(int val) {
  if(this.mHealth > val) {
    this.mHealth -= val;
  } else {
    this.mHealth = 0;
}

如果没有setter,你需要在改变字段的任何地方使用这个逻辑。你也可以在这个方法中包括检查角色是否佩戴了精神无敌的戒指: - )

答案 5 :(得分:0)

警告

您正在混合两个相关问题。


问题:

[1]我应该使用直接访问字段,还是通过加速器方法访问字段(“getter”和“setter”)。

[2]在这两种情况下,哪些访问修饰符应该适用?


简短快速回答

[1]我应该使用直接访问字段,还是通过加速器方法访问字段(“getter”和“setter”)。

Go,对于“访问者方法访问字段”a.k.a.“getter(s)and setter(s)”。另一种方法没有错,这取决于你想做什么。

[2]在这两种情况下,哪些访问修饰符应该适用?

如果您选择“普通字段”,请使用“公开”,除非有特定原因使用“私有”或“受保护”。如果你选择“加速器方法”,对字段使用“protected”,对加法器使用“protected”或“public”。


长期无聊的答案

[1]我应该使用直接访问字段,还是通过加速器方法访问字段(“getter”和“setter”)。

转到“按访问者方法访问字段”a.k.a.“getter(s)and setter(s)”。

另一种方法没有错,这取决于你想做什么。

但是,由于这些方法可以覆盖属性访问,因此可以通过方法添加,删除或更改更多功能。

我建议,为数据对象保留“普通字段”。

[2]在这两种情况下,哪些访问修饰符应该适用?

如果您选择“普通字段”,请使用“公开”,除非有特定原因使用“私人”或“受保护”。

如果你选择“加速器方法”,则对字段使用“protected”,对加法器使用“protected”或“public”。

对加密者的字段应用“公共”访问权限不是一个好主意,因为这样,你会让自己和你的类的其他程序员用户感到困惑, 在哪一个上直接使用。

代码示例:

public class ControlClass {
    // example of non private field (s)
    protected String controlname;

    // ...

    // example of non private field (s)
    protected int width;
    protected int height;

    // ...

    // example of read-only property
    public final String getControlName()
    {
        return this.controlname;
    } // String getControlName(...)

    // ...

    @Override
    public int getWidth()
    {
        return this.width;
    } // int getWidth(...)

    @Override 
    public void setWidth(int newvalue)
    {
        this.width = newvalue;
    } // void setWidth(...)

    @Override
    public int getHeight()
    {
        return this.height;
    } // int getHeight(...)

    @Override 
    public void setHeight(int newvalue)
    {
        this.height = newvalue;
    } // void setHeight(...)

    // ...

    // constructor assigns initial values to properties' fields
    public ControlClass(){
        this.controlname = "control";
        this.height = 0;
        this.width = 0;
    } // ControlClass(...)

    // ...
} // class ControlClass

public class ButtonClass extends ControlClass {
    // ...

    // example of overriden public property with non public field
    @Override
    public int getWidth()
    {
        if (this.width < 5)
          return 5
        else
          return this.width;
    } // int getWidth(...)

    // example of overriden public property with non public field
    @Override 
    public void setWidth(int newvalue)
    {
        if (newvalue < 5)
          throw new ArithmeticException("integer underflow");

        this.width = newvalue;
    } // void setWidth(...)

    // example of overriden public property with non public field
    @Override
    public int getHeight()
    {
        if (this.height < 5)
          return 5
        else
          return this.height;
    } // int getHeight(...)

    // example of overriden public property with non public field
    @Override 
    public void setHeight(int newvalue)
    {
        if (newvalue < 5)
          throw new ArithmeticException("integer underflow");

        this.height = newvalue;
    } // void setHeight(...)

    // ...

    // constructor assigns initial values to properties' fields
    public ControlClass(){
        this.controlname = "ButtonClass";
        this.height = 5;
        this.width = 5;
    } // ButtonClass(...) 

    // ...
} // class ControlClass

我开始使用“私人”字段,像许多程序员一样,购买,最终,不得不改为“受保护”,因为有时需要使用它。直接


其他评论。

我使用其他面向对象的编程语言,有自己的“属性”方式和语法,这给你另一个视角。

如Object Pascal(a.k.a。“Delphi”),ECMAScript(“Javascript”),C ++,C#。请注意,Delphi和C#支持“完整属性”,而不仅仅是加速器方法或字段,这为开发人员提供了另一种设计对象和面向类的软件应用程序的方法。

这与Java有什么关系?

当我用Java或C ++设计一个类时,我设计属性,就像C#或Delphi一样,设计一个独立于字段或方法的概念,即使可以存在由他们实施。


干杯。