首页 文章

为什么要使用getter和setter / accessors? [关闭]

提问于
浏览
1354

使用getter和setter的优点是什么 - 只能获取和设置 - 而不是简单地为这些变量使用公共字段?

如果getter和setter做的不仅仅是简单的获取/设置,我可以非常快地解决这个问题,但我不是100%清楚如何:

public String foo;

更糟糕的是:

private String foo;
public void setFoo(String foo) { this.foo = foo; }
public String getFoo() { return foo; }

而前者需要更少的样板代码 .

30 回答

  • 3

    此外,这是为了“面向未来”你的 class . 特别是,从字段更改为属性是ABI中断,所以如果你以后确定你需要更多逻辑而不仅仅是“设置/获取字段”,那么你需要打破ABI,这当然会产生任何问题其他已经针对你的课程编译 .

  • 76

    Getter和setter方法是访问器方法,这意味着它们通常是更改私有类成员的公共接口 . 您使用getter和setter方法来定义属性 . 您可以将getter和setter方法作为类外的属性进行访问,即使您在类中将它们定义为方法也是如此 . 类外的这些属性可以与类中的属性名称具有不同的名称 .

    使用getter和setter方法有一些优点,例如能够让您创建具有可以像属性一样访问的复杂功能的成员 . 它们还允许您创建只读和只写属性 .

    尽管getter和setter方法很有用,但是你应该注意不要过度使用它们,因为在某些情况下,它们会使代码维护变得更加困难 . 此外,它们还提供对类实现的访问,例如公共成员 . OOP练习不鼓励直接访问课程中的属性 .

    编写类时,始终鼓励您尽可能多地将实例变量设为私有,并相应地添加getter和setter方法 . 这是因为有几次您可能不想让用户更改类中的某些变量 . 例如,如果您有一个私有静态方法来跟踪为特定类创建的实例数,则您不希望用户使用代码修改该计数器 . 只有构造函数语句应该在调用时递增该变量 . 在这种情况下,您可以创建一个私有实例变量并仅为计数器变量提供getter方法,这意味着用户只能使用getter方法检索当前值,并且它们将无法设置新值使用setter方法 . 在没有setter的情况下创建getter是一种简单的方法,可以将类中的某些变量设置为只读 .

  • 14

    您应该在以下情况下使用getter和setter:

    • 你正在处理概念上属于某个属性的东西,但是:

    • 您的语言不是't have properties (or some similar mechanism, like Tcl' s变量曲线),或

    • 您的语言's property support isn'足以满足此用例,或者

    • 您的语言's (or sometimes your framework' s)惯用惯例鼓励此用例的getter或setter .

    所以这很少是一般的OO问题;这是一个特定于语言的问题,针对不同的语言(和不同的用例)有不同的答案 .


    从OO理论的角度来看,吸气剂和制定者是无用的 . 你的类的接口是它的作用,而不是它的状态 . (如果没有,你写错了类 . )在非常简单的情况下,类所做的只是,例如,表示直角坐标中的一个点,*属性是接口的一部分;吸气剂和孵化器只是 Cloud . 但是在任何非常简单的情况下,属性,getter和setter都不是接口的一部分 .

    换句话说:如果你认为你班上的消费者甚至不知道你有一个 spam 属性,更不用说能够无所畏惧地改变它,那么给他们一个 set_spam 方法是你想要做的最后一件事 .

    *即使对于那个简单的类,您也可能不一定要允许设置x和y值 . 如果这真的是一个类,不应该有翻译,旋转等方法吗?如果它只是一个类,因为你的语言没有记录/结构/命名元组,那么这不是OO的问题......


    但没有人会做一般的OO设计 . 他们用特定的语言进行设计和实施 . 在某些语言中,getter和setter远非无用 .

    如果您的语言没有属性,那么表示概念上属性但实际计算或验证的东西的唯一方法是通过getter和setter .

    即使您的语言确实具有属性,也可能存在不足或不合适的情况 . 例如,如果要允许子类控制属性的语义,则在没有动态访问的语言中,子类不能将计算属性替换为属性 .

    至于“如果我想稍后改变我的实现怎么办?”问题(重复在OP的问题和接受的答案中多次使用不同的措辞):如果它真的是纯粹的实现更改,并且您从属性开始,则可以将其更改为属性而不影响接口 . 当然,除非你的语言不支持 . 所以这真的只是同样的情况 .

    此外,遵循您正在使用的语言(或框架)的习语非常重要 . 如果你用C#编写漂亮的Ruby风格代码,那么除了你之外的任何有经验的C#开发人员都会在阅读它时遇到麻烦,这很糟糕 . 有些语言围绕其惯例的文化比其他语言更强.- Java和Python可能并不是巧合,而Java和Python恰好具有两种最强大的文化 .

    除了人类读者之外,还有一些图书馆和工具可以让您遵守惯例,如果不这样做,会让您的生活更加艰难 . 挂钩Interface Builder小部件除了ObjC属性之外的任何东西,或者使用某些没有getter的Java模拟库,只会让你的生活变得更加困难 . 如果这些工具对您很重要,请不要与它们作斗争 .

  • 410

    我们使用getter和setter:

    • 可重用性

    • 在编程的后期阶段执行验证

    Getter和setter方法是访问私有类成员的公共接口 .


    封装口头禅

    封装口头禅是将字段设为私有,方法是公共的 .

    Getter方法:我们可以访问私有变量 . Setter方法:我们可以修改私有字段 .

    即使getter和setter方法没有添加新功能,我们也可以改变主意,稍后再回来制作该方法

    • 更好;

    • 更安全;和

    • 更快 .


    在可以使用值的任何地方,可以添加返回该值的方法 . 代替:

    int x = 1000 - 500
    

    使用

    int x = 1000 - class_name.getValue();
    

    外行人的说法

    Representation of "Person" class

    假设我们需要存储此 Person 的详细信息 . 这个 Person 的字段为 nameagesex . 这样做涉及为 nameagesex 创建方法 . 现在,如果我们需要创建另一个人,则有必要再次为 nameagesex 创建方法 .

    我们可以使用getter和setter方法创建一个bean class(Person) ,而不是这样做 . 所以明天我们可以在需要添加新人时创建这个Bean class(Person class) 的对象(参见图) . 因此,我们重用bean类的字段和方法,这要好得多 .

  • 1

    从面向对象设计的角度来看,两种替代方案都可能通过削弱类的封装来破坏代码的维护 . 有关讨论,您可以查看这篇优秀的文章:http://typicalprogrammer.com/?p=23

  • 9

    因为从现在起2周(几个月,几年),当你意识到你的setter需要做 more 而不仅仅是设置值时,你也会意识到该属性已被直接用于其他238个类:-)

  • 28

    原因很多 . 我最喜欢的是当你需要改变行为或规范你可以在变量上设置的内容时 . 例如,假设您有一个setSpeed(int speed)方法 . 但是你想要你只能设置100的最高速度 . 你会做的事情如下:

    public void setSpeed(int speed) {
      if ( speed > 100 ) {
        this.speed = 100;
      } else {
        this.speed = speed;
      }
    }
    

    现在如果您的代码中使用公共字段,然后您意识到您需要上述要求,该怎么办?尽情享受公共领域的每一次使用,而不仅仅是修改你的二传手 .

    我2美分:)

  • 2

    公共字段并不比除了返回字段并分配给它之外什么都不做的getter / setter对更差 . 首先,很明显(在大多数语言中)没有功能差异 . 任何差异必须与其他因素有关,例如可维护性或可读性 .

    getter / setter对的一个常见的优点是,你声称你可以改变实现,而你的客户甚至不需要了解它 . 但是,向setter添加验证是对其前提条件的更改, a violation of the previous contract ,非常简单,"you can put anything in here, and you can get that same thing later from the getter" .

    因此,既然您违反了 Contract ,那么更改代码库中的每个文件都是您应该要做的事情,而不是避免 . 如果你避免它,你就假设所有代码都假设这些方法的 Contract 是不同的 .

    如果那不应该是 Contract ,那么接口允许客户端将对象置于无效状态 . 这与封装完全相反如果该字段从一开始就无法真正设置为任何东西,为什么从一开始就没有验证呢?

    这个相同的论点适用于这些传递的getter / setter对的其他假设优势:如果你以后决定更改所设置的值,那么你就违反了 Contract . 如果覆盖派生类中的默认功能,则会超出一些无害的修改(如日志记录或其他不可观察的修改)行为),你打破了基类的 Contract . 这违反了Liskov Substitutability Principle,这被视为OO的原则之一 .

    如果一个类对每个字段都有这些愚蠢的getter和setter,那么它就是一个没有任何不变量的类,没有 Contract . 这真的是面向对象的设计吗?如果所有课程都是那些吸气者和制定者,那么它只是一个愚蠢的数据持有者,而愚蠢的数据持有者应该看起来像愚蠢的数据持有者:

    class Foo {
    public:
        int DaysLeft;
        int ContestantNumber;
    };
    

    将传递getter / setter对添加到这样的类中不会增加任何值 . 其他类应该提供有意义的操作,而不仅仅是已经提供的字段的操作 . 这就是你如何定义和维护有用的不变量 .

    客户:“我能用这个类的对象做什么?”设计师:“你可以读写几个变量 . ”客户:“哦......很酷,我猜?”

    有理由使用getter和setter,但如果这些原因不存在,那么以false封装之神的名义制作getter / setter对并不是一件好事 . 制作getter或setter的有效理由包括经常提到的事情,因为您可以在以后做出可能的更改,例如验证或不同的内部表示 . 或者值可能是客户端可读但不可写(例如,读取字典的大小),因此简单的getter是一个不错的选择 . 但是当你做出选择时,这些原因应该存在,而不仅仅是你以后想要的潜在事物 . 这是YAGNI的一个例子(你不需要它) .

  • 833

    另一种用法(在支持属性的语言中)是setter和getter可以暗示操作是非平凡的 . 通常,您希望避免在属性中执行任何计算成本高昂的操作 .

  • 23

    我想抛出注释的想法:@getter和@setter . 使用@getter,您应该能够obj = class.field但不能使用class.field = obj . 使用@setter,反之亦然 . 使用@getter和@setter,你应该能够做到这两点 . 这将保留封装并通过在运行时不调用简单方法来减少时间 .

  • 16

    代码发展 . private 适用于需要数据成员保护的情况 . 最终所有的类都应该是"miniprograms",它们具有明确定义的接口,你不能只是拧紧内部的 .

    也就是说,软件开发并没有在第一次尝试时压制一些铸铁雕像 . 当你使用它时,代码更像是粘土 . It evolves 当您开发它并了解有关您正在解决的问题域的更多信息时 . 在开发过程中,类可能会相互影响而不是它们应该相互作用(您计划将因子分解出来),合并在一起或分开 . 所以我认为辩论归结为那些不想虔诚写作的人

    int getVar() const { return var ; }
    

    所以你有了:

    doSomething( obj->getVar() ) ;
    

    代替

    doSomething( obj->var ) ;
    

    不仅 getVar() 在视觉上有噪音,它给人的幻觉是 gettingVar() 在某种程度上是一个比实际更复杂的过程 . 你(作为 class 作家)如何看待 var 的神圣性,对于你 class 的用户来说尤其令人困惑,如果它有一个旁路安装者 - 那么看起来你正在把这些大门放到"protect"你坚持认为有 Value 的东西,( var )的神圣性,但即使你承认任何人只要进入他们想要的任何 Value 的能力,而你甚至不会窥视他们正在做的事情 .

    所以我编程如下(假设一种"agile"类型的方法 - 即当我编写的代码不知道它将要做什么/没有时间或经验来规划精心设计的瀑布式接口集时):

    1)从所有公共成员开始,获取具有数据和行为的基本对象 . 这就是为什么在我所有的C "example"代码中你都会注意到我使用的是 struct 而不是 class .

    2)当一个对象的数据成员的内部行为变得足够复杂时(例如,它喜欢以某种顺序保持内部 std::list ),写入访问器类型函数 . 因为我总是立即设置成员 private ,但是在该类的演变的某个地方,成员将"promoted"到 protectedprivate .

    3)完全充实并且对其内部有严格规则的类(即他们确切地知道他们正在做什么,并且你不得使用其内部成员)给予 class 指定,默认私人成员,以及只有少数几个成员被允许 public .

    我发现这种方法可以让我避免坐在那里,并且在课堂演变的早期阶段,当许多数据成员被迁移出去,转移等时,他们会虔诚地写下getter / setter .

  • 12

    很多人都在谈论吸气者和制定者的优势,但我想扮演魔鬼的拥护者 . 现在我正在调试一个非常大的程序,程序员决定让所有程序都得到getter和setter . 这可能看起来不错,但它是一个逆向工程的噩梦 .

    假设您正在查看数百行代码,并且您遇到了这样的问题:

    person.name = "Joe";
    

    这是一段非常简单的代码,直到你意识到它是一个二传手 . 现在,你跟着那个setter,发现它还设置了person.firstName,person.lastName,person.isHuman,person.hasReallyCommonFirstName,并调用了person.update(),它将查询发送到数据库等等 . 哦,那是你的内存泄漏发生的地方 .

    乍看之下理解本地代码是一个具有良好可读性的重要特性,因为getter和setter往往会破坏 . 这就是为什么我尽可能地避免使用它们,并尽量减少使用它们时所做的事情 .

  • 1

    我花了很长时间考虑Java案例,我相信真正的原因是:

    • Code to the interface, not the implementation

    • Interfaces only specify methods, not fields

    换句话说,您可以在界面中指定字段的唯一方法是提供用于编写新值的方法和用于读取当前值的方法 .

    那些方法是臭名昭着的吸气者和制定者....

  • 45

    它对于延迟加载很有用 . 假设有问题的对象存储在数据库中,除非您需要,否则您不希望得到它 . 如果对象是由getter检索的,那么内部对象可以为null,直到有人要求它为止,然后你可以在第一次调用getter时获取它 .

    我在一个项目中有一个基页类,它是从一些不同的Web服务调用中加载一些数据,但是这些Web服务调用中的数据并不总是在所有子页面中使用 . Web服务,为了所有的好处,开创了“慢”的新定义,因此如果您不需要,您不希望进行Web服务调用 .

    我从公共字段移动到getter,现在getter检查缓存,如果没有,则调用Web服务 . 因此,通过一点包装,可以防止大量的Web服务调用 .

    因此,getter使我无法在每个子页面上弄清楚我需要什么 . 如果我需要它,我会打电话给吸气器,如果我还没有它,它就会找到它 .

    protected YourType _yourName = null;
        public YourType YourName{
          get
          {
            if (_yourName == null)
            {
              _yourName = new YourType();
              return _yourName;
            }
          }
        }
    
  • 14

    到目前为止我在答案中遗漏的一个方面是访问规范:

    • 对于成员,您只有一个设置和获取的访问规范

    • 对于setter和getter,您可以对其进行微调并单独定义

  • 2

    There are actually many good reasons to consider using accessors 而不是直接暴露类的字段 - 不仅仅是封装的参数,使未来的更改更容易 .

    以下是我所知道的一些原因:

    • 与获取或设置属性相关联的行为的封装 - 这允许以后更容易添加其他功能(如验证) .

    • 在使用替代表示公开属性的同时隐藏属性的内部表示 .

    • 使公共接口免受更改 - 允许公共接口在实现更改时保持不变,而不会影响现有使用者 .

    • 控制属性的生命周期和内存管理(处置)语义 - 在非托管内存环境(如C或Objective-C)中尤为重要 .

    • 为属性在运行时更改时提供调试拦截点 - 在某些语言中调试属性更改为特定值的时间和位置可能非常困难 .

    • 改进了与旨在针对属性获取器/设置器进行操作的库的互操作性 - 脑海中浮现了模拟,序列化和WPF .

    • 允许继承者通过重写getter / setter方法来更改属性的行为和语义的语义 .

    • 允许getter / setter作为lambda表达式而不是值传递 .

    • getter和setter可以允许不同的访问级别 - 例如get可以是公共的,但是set可以受到保护 .

  • 22

    有一个很好的理由考虑使用访问器是没有属性继承 . 见下一个例子:

    public class TestPropertyOverride {
        public static class A {
            public int i = 0;
    
            public void add() {
                i++;
            }
    
            public int getI() {
                return i;
            }
        }
    
        public static class B extends A {
            public int i = 2;
    
            @Override
            public void add() {
                i = i + 2;
            }
    
            @Override
            public int getI() {
                return i;
            }
        }
    
        public static void main(String[] args) {
            A a = new B();
            System.out.println(a.i);
            a.add();
            System.out.println(a.i);
            System.out.println(a.getI());
        }
    }
    

    输出:

    0
    0
    4
    
  • 10

    在纯粹的面向对象的世界中,getter和setter是 terrible anti-pattern . 阅读这篇文章:Getters/Setters. Evil. Period . 简而言之,它们鼓励程序员将对象视为数据结构,这种思维方式纯粹是程序性的(如COBOL或C) . 在面向对象的语言中,没有数据结构,只有暴露行为的对象(不是属性/属性!)

    您可以在Elegant Objects的第3.5节(我的关于面向对象编程的书)中找到更多关于它们的信息 .

  • 14

    访问器和更改器的一个优点是您可以执行验证 .

    例如,如果 foo 是公共的,我可以轻松地将其设置为 null 然后其他人可以尝试在对象上调用方法 . 但它不再存在了!使用 setFoo 方法,我可以确保 foo 永远不会设置为 null .

    访问器和更改器也允许封装 - 如果您不应该在设置后看到值(也许它是在构造函数中设置然后由方法使用,但从不应该被更改),任何人都不会看到它 . 但是,如果您可以允许其他类查看或更改它,您可以提供适当的访问者和/或更改者 .

  • 318

    取决于您的语言 . 你已经标记了这个“面向对象”而不是“Java”,所以我想指出ChssPly76的答案是依赖于语言的 . 例如,在Python中,没有理由使用getter和setter . 如果需要更改行为,可以使用属性,该属性围绕基本属性访问包装getter和setter . 像这样的东西:

    class Simple(object):
       def _get_value(self):
           return self._value -1
    
       def _set_value(self, new_value):
           self._value = new_value + 1
    
       def _del_value(self):
           self.old_values.append(self._value)
           del self._value
    
       value = property(_get_value, _set_value, _del_value)
    
  • 36

    好吧,我只想补充一点,即使有时它们对于变量/对象的封装和安全性是必要的,如果我们想编写一个真正的面向对象程序,那么我们需要 STOP OVERUSING THE ACCESSORS ,因为有时我们在很大程度上依赖于它们并不是真的有必要,这几乎就像我们把变量公之于众一样 .

  • 3

    getter / setter的一个相对现代的优点是可以更容易地在标记(索引)代码编辑器中浏览代码 . 例如 . 如果要查看谁设置了成员,可以打开setter的调用层次结构 .

    另一方面,如果该成员是公共的,则这些工具无法过滤对该成员的读/写访问权限 . 因此,你必须跋涉这个成员的所有用途 .

  • 2

    谢谢,这真的澄清了我的想法 . 现在这里(差不多)10个(几乎)很好的理由不使用getter和setter:

    • 当您意识到您需要做的不仅仅是设置和获取值时,您可以将该字段设为私有,这将立即告诉您直接访问它的位置 .

    • 您在那里执行的任何验证只能是无上下文,实际上很少进行验证 .

    • 您可以更改正在设置的值 - 当调用者向您传递他们[震惊恐怖]希望您按原样存储的值时,这绝对是一场噩梦 .

    • 你可以隐藏内部表示 - 太棒了,所以你确保所有这些操作都是对称的吗?

    • 你've insulated your public interface from changes under the sheets - if you were designing an interface and weren'确定直接访问某些东西是否正常,那么你应该继续设计 .

    • 有些库期望这个,但不是很多 - 反射,序列化,模拟对象都可以正常使用公共字段 .

    • 继承此类,您可以覆盖默认功能 - 换句话说,您可以通过隐藏实现但使其不一致来真正混淆调用者 .

    我刚离开的最后三个(N / A或D / C)......

  • 21

    在面向对象语言中,方法及其访问修饰符声明该对象的接口 . 在构造函数和访问器以及mutator方法之间,开发人员可以控制对对象内部状态的访问 . 如果变量只是公开声明,则无法管理该访问 . 当我们使用setter时,我们可以限制用户输入我们需要的输入 . 意味着该变量的馈送将通过适当的通道,并且通道由我们预定义 . 因此使用setter更安全 .

  • 2

    我知道有点晚了,但我认为有些人对性能很感兴趣 .

    我做了一点性能测试 . 我写了一个类"NumberHolder",好吧,它持有一个整数 . 您可以使用getter方法 anInstance.getNumber() 或通过使用 anInstance.number 直接访问该数字来读取该Integer . 我的程序通过两种方式读取数字1,000,000,000次 . 该过程重复五次并打印时间 . 我得到以下结果:

    Time 1: 953ms, Time 2: 741ms
    Time 1: 655ms, Time 2: 743ms
    Time 1: 656ms, Time 2: 634ms
    Time 1: 637ms, Time 2: 629ms
    Time 1: 633ms, Time 2: 625ms
    

    (时间1是直接的方式,时间2是吸气剂)

    你看,吸气剂(几乎)总是快一点 . 然后我尝试了不同的循环次数 . 而不是100万,我使用了1000万和10万 . 结果:

    1000万次循环:

    Time 1: 6382ms, Time 2: 6351ms
    Time 1: 6363ms, Time 2: 6351ms
    Time 1: 6350ms, Time 2: 6363ms
    Time 1: 6353ms, Time 2: 6357ms
    Time 1: 6348ms, Time 2: 6354ms
    

    1000万次循环,时间几乎相同 . 这里有10万(10万)个周期:

    Time 1: 77ms, Time 2: 73ms
    Time 1: 94ms, Time 2: 65ms
    Time 1: 67ms, Time 2: 63ms
    Time 1: 65ms, Time 2: 65ms
    Time 1: 66ms, Time 2: 63ms
    

    同样具有不同的循环量,吸气剂比常规方式快一点 . 我希望这对你有帮助 .

  • 44

    面向对象设计的基本原则之一: Encapsulation!

    它为您提供了许多好处,其中之一是您可以在幕后更改getter / setter的实现,但只要数据类型保持不变,该值的任何使用者都将继续工作 .

  • 6

    除非当前交付需要,否则不要使用吸气剂设定器 . 如果要在大多数 生产环境 应用程序系统中更改其更改请求,请不要过多考虑将来会发生什么 .

    想想简单,容易,在需要时增加复杂性 .

    我不会利用对深度技术知识的企业主的无知,因为我认为这是正确的,或者我喜欢这种方法 .

    我有大量的系统编写没有getter setter只有访问修饰符和一些方法来验证n执行业务逻辑 . 如果你绝对需要的 . 用什么 .

  • 4

    编辑:我回答了这个问题,因为有很多人在学习编程问这个问题,而且大多数答案在技术上都非常有用,但如果你是新手,它们就不那么容易理解了 . 我们都是新手,所以我想我会尝试一个更新手友好的答案 .

    两个主要的是多态性和验证 . 即使它只是一个愚蠢的数据结构 .

    假设我们有这个简单的类:

    public class Bottle {
      public int amountOfWaterMl;
      public int capacityMl;
    }
    

    一个非常简单的类,它包含多少液体,以及它的容量(以毫升为单位) .

    我这样做会发生什么:

    Bottle bot = new Bottle();
    bot.amountOfWaterMl = 1500;
    bot.capacity = 1000;
    

    好吧,你不会指望这样做,对吗?你希望有一些理智的检查 . 更糟糕的是,如果我从未指定最大容量怎么办?亲爱的,我们有问题 .

    但是还有另一个问题 . 如果瓶子只是一种容器怎么办?如果我们有几个容器,所有容器和液体填充量怎么办?如果我们可以创建一个界面,我们可以让我们程序的其余部分接受该界面,瓶子,塑料桶和各种东西都可以互换 . 那不是更好吗?由于接口需要方法,这也是一件好事 .

    我们最终得到的结果如下:

    public interface LiquidContainer {
      public int getAmountMl();
      public void setAmountMl(int amountMl);
      public int getCapacityMl();
      public void setCapcityMl(int capacityMl);
    }
    

    大!现在我们只需将Bottle更改为:

    public class Bottle extends LiquidContainer {
      private int capacityMl;
      private int amountFilledMl;
      public Bottle(int capacityMl, int amountFilledMl) {
        this.capacityMl = capacityMl;
        this.amountFilledMl = amountFilledMl;
        checkNotOverFlow();
      }
    
      public int getAmountMl() {
        return amountFilledMl;
      }
    
      public void setAmountMl(int amountMl) {
         this.amountFilled = amountMl;
         checkNotOverFlow();
      }
      public int getCapacityMl() {
        return capacityMl;
      public void setCapcityMl(int capacityMl) {
        this.capacityMl = capacityMl;
        checkNotOverFlow();
      }
    
      private void checkNotOverFlow() {
        if(amountOfWaterMl > capacityMl) {
          throw new BottleOverflowException();
        }
    }
    

    我将把BottleOverflowException的定义留给读者作为练习 .

    现在注意这是多么强大 . 我们现在可以通过接受LiquidContainer而不是Bottle来处理代码中的任何类型的容器 . 这些瓶子如何处理这些东西都可能有所不同 . 您可以将瓶子在更改时将其状态写入磁盘,或者保存在SQL数据库或GNU上的瓶子知道还有什么 .

    所有这些都可以有不同的方式来处理各种各样的情绪 . Bottle只是检查它是否溢出它会抛出RuntimeException . 但这可能是错误的做法 . (关于错误处理有一个有用的讨论,但是我在这里有目的地保持它非常简单 . 评论中的人可能会指出这种简单方法的缺陷 . ;))

    是的,似乎我们从一个非常简单的想法转变为快速获得更好的答案 .

    还有第三件事并不是每个人都能解决的问题:Getters和setter使用方法调用 . 这意味着它们看起来像其他地方的普通方法 . 而不是为DTO和东西提供奇怪的特定语法,你到处都有同样的东西 .

  • 4

    Getterssetters 用于实现面向对象编程的两个基本方面:

    • 抽象

    • 封装

    假设我们有一个Employee类:

    package com.highmark.productConfig.types;
    
    public class Employee {
    
        private String firstName;
        private String middleName;
        private String lastName;
    
        public String getFirstName() {
          return firstName;
        }
        public void setFirstName(String firstName) {
           this.firstName = firstName;
        }
        public String getMiddleName() {
            return middleName;
        }
        public void setMiddleName(String middleName) {
             this.middleName = middleName;
        }
        public String getLastName() {
            return lastName;
        }
        public void setLastName(String lastName) {
            this.lastName = lastName;
        }
    
        public String getFullName(){
            return this.getFirstName() + this.getMiddleName() +  this.getLastName();
        }
     }
    

    这里,全名的实现细节对用户是隐藏的,并且不能直接向用户访问,这与公共属性不同 .

  • 3

    在不支持“属性”(C,Java)或需要在将字段更改为属性(C#)时重新编译客户端的语言中,使用get / set方法更容易修改 . 例如,将验证逻辑添加到setFoo方法不需要更改类的公共接口 .

    在支持“真实”属性的语言(Python,Ruby,也许是Smalltalk?)中,没有必要获取/设置方法 .

相关问题