面向对象编程私有class字段+get/set还是publicclass字段?

Object-Oriented programming private class field + get / set or public class field?

我是一名初级开发人员(目前正在练习 Java),我对我的代码的正确性有一个疑问,这里有一个例子: 我正在 Java 上编写一个简单的 MMO 游戏表示,我有 2 classes(角色和法术)。 角色具有属性(mName、mHealth 和 mEnergy),法术 class 具有属性(mSpellName、mSpellCost、mSpellDamage)。而Spellclass也有一个方法叫做execute,下面是一段代码

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

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

Getters/setters 更好,因为它封装或隐藏了实际 class 为设置该数据所做的工作。将构造函数设置为private,让它初始化默认值,然后用户可以调用set方法设置变量。

你说得对,编写好的代码很重要,但一开始掌握面向对象编程可能有点困难。

在这种情况下,我建议将 spellExecute 移动到类似的方法,除了字符 class :

public void didUseSpell(Spell spell) {
    this.mEnergy -= spell.spellCost;
}

public void wasHitBySpell(Spell spell) {
    this.mHealth -= spell.spellDamage;
}

在你的拼写执行方法中,你会调用:

public void spellExecute(Character caster, Character target) {
    caster.didUseSpell(this);
    target.wasHitBySpell(this);
}

总的来说,解决这个问题有很多不同的方法,它们在代码的简洁性和冗长性方面都有所不同。另一种解决方案是为受法术影响的字段创建 getter and setter methods

Getter 和 setter 是首选 - 毕竟,如果您不打算使用它的主要功能,为什么要使用面向对象的语言?

在这种情况下使用设置器,您可以轻松地执行完整性规则,而无需每个调用者都重复逻辑,例如- 在角色中尝试:

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

如果没有设置器,您将在更改字段的任何地方都需要此逻辑。您还可以在此方法中包括诸如检查角色是否也戴着精神无敌戒指之类的东西:-)

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

使用您的 class 的任何其他 class 应该只能按照您描述的方式访问和更改您的字段。

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

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 方法可以保护该字段免受外部影响。它仍然可以被操纵,但是只能以我们希望允许它被操纵的方式。另请注意,此字段根本没有设置方法:我们不希望用户能够设置自己的价格,只能设置我们指定的价格!

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

Getter和setter(Javabean)比较多better.It也提供封装feature.Which对隐藏数据很有用

  private int id;

    public int getId() {
            return id;
    }

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

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

具有私有字段的 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 等)都遵循这些命名约定。希望这能回答您的问题。

警告

你把两个相关的问题混在一起了。


问题:

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

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


简短快速回答

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

去吧,为了"fields access by accessor methods"a.k.a。 "getter (s) and setter (s)"。另一种方法没有错,这取决于你想做什么。

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

如果您选择 "plain fields",请使用 "public",除非有特定原因需要使用 "private" 或 "protected"。如果您选择 "accesors methods",请对字段使用 "protected",对访问器使用 "protected" 或 "public"。


冗长无聊的扩展答案

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

去吧,为了"fields access by accessor methods"a.k.a。 "getter (s) and setter (s)".

其他方法没有错,看你想做什么。

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

我建议,为数据对象保留 "plain fields"。

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

如果您选择 "plain fields",请使用 "public",除非有特定原因使用 "private" 或 "protected"。

如果您选择 "accesors methods",请对字段使用 "protected",对访问器使用 "protected" 或 "public"。

对访问器字段应用 "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

我开始使用"private"作为字段,和很多程序员一样,买了,最后不得不改成"protected",因为有时候需要用到。直接。


附加评论。

我使用过其他面向对象的编程语言,它们有自己的方式和语法 "properties",这给了你另一个视角。

例如 Object Pascal(a.k.a."Delphi")、ECMAScript("Javascript")、C++、C#。请注意,Delphi 和 C# 支持 "full properties",而不仅仅是访问器方法或字段,这为开发人员提供了另一种设计对象和 Class 面向软件应用程序的方法。

这跟Java有什么关系?

当我在 Java 或 C++ 中设计 Class 时,我将设计属性,就像 C# 或 Delphi 一样,一个独立于字段或方法的概念,即使它们可以实现。


干杯。