把你的帽子提一步到探索者和突变者
面向对象(1)我记得当我第一次在大学学习编程的时候,老师们提到我们应该总是使用mutator和accessor来检索和修改面向对象代码中的数据。当然,我们称之为setter和getter方法,大多数学生都讨厌它们。我特别记得一个学生拒绝使用它们,因为它们“愚蠢”。据说,他——当然——现在是一名专业程序员。
我认为许多新程序员对访问者和突变者的错误了解,我认为它是关于的很少的解释为什么任何人都应该关心。教授们可能会提到,学生应该总是使用setter/getter对来处理与他们的数据的交互,但我从来没有听到过关于它们为什么重要的解释。当你学习编程的时候,你会被新的信息压得喘不过气来,大脑会扔掉它不理解或认为无关紧要的东西。那个认为自己很愚蠢的学生提出了这样的论点:他们只是从传统中脱颖而出,不值得写那些代码。
但是,我编程的时间越长,我越看到了突变和访问器方法的微妙价值。
延迟初始化
我第一次看到访问者方法中的值是如何使用Java的Swing Graphics包。该类使用Visual Eclipse,为您生成大部分代码,并且我注意到应用程序首次运行时初始化了很少的变量,但大多数事情都在其存档器中初始化。
而不是YORE的毫无意义的配件:
上市jlist.getpersonlist.(){返回姓氏;}
我开始看到实际做某事的访问者:
上市jlist.getpersonlist.(){如果(姓氏==.空值){姓氏=新的jlist.(Getpersons.());姓氏。setcellRenderer.(GetMyCustomRenderer.());姓氏。setPrototyPecellvalue.(“最初的”);姓氏。setpreferredsize.(新的java.。awt公司。尺寸(100那200.));}返回姓氏;}
突然间的突然传感器的价值变得更加清晰。您可以使用它来初始化对象中的变量,但仅在实际需要它们时才才能。如果你只在罕见的情况下使用某种变量,那就是很好的,除非你实际上在那个罕见的情况下,否则它不会被初始化。或者也许您有很多计算要求苛刻的计算,但您只需要一部分结果在任何给定的时间,即延迟初始化 - 访问者的第一个福音 - 将有助于支付这些成本。
在更高级的问题中,您可以实现动态编程算法,仅生成和缓存您实际感兴趣的值,并将其全部隐藏在访问器后面:
-(ID)valueatx:(㈡)X安迪:(㈡)y{ID瓦=[自己cachedvalueforx:X安迪:y];如果(瓦==.零){//使用动态程序生成值}返回瓦;}
这可以是提高性能的重要方法,而无需向类公共API添加任何复杂性。
访问控制
访问器的另一个用法是验证是否允许访问对象使用某个访问器。也许您只希望关联的主对象能够使用访问器方法:
-(nsnumber.*)SSN:(nsobject.*)发件人{如果(发件人!=[自己MasterObject.])返回零;返回SSN.;}
一个非常简单的例子,但是你可以把它推广到更有用的情况。例如,在多个程序之间共享的分布式对象,需要保护某些数据不被过于自由地访问。
突变者
好的,所以我们看看辅助商很重要的一些原因,现在让我们考虑突变者。verators的论点有点自我明显,但无论如何都值得检查。
数据验证
您通常希望在更新之前验证更新是否有效,并且verators是最完美的地方。
defsetname.(自己那新名字):如果Len.(新名字)<3.:增加tooshortnameexception.那你“你的名字太短了!”el新名字在[“鲍勃”那“吉姆”那“乔”]:增加awfulnameexception.那你“你姓名的质量是不合格的。”el新名字。包含(“teh”):增加ihateinternetspellingException.那你“只是回家。”自己。名称=新名字
做清理和设置
此外,当您使用virator时,您可以在更新新的值之前对先前的值进行清理。例如,您可能有一个文件到频繁写入的文件,并且您需要关闭它,以及打开新文件的流。
defsetfile.(自己那新文件):如果新文件!=自己。文件:自己。文件。关闭()自己。文件=新文件自己。文件。打开()
这对于没有自动垃圾收集的语言尤其重要,但偶尔收集的螯合偶尔需要一些显式清理(例如,打破链接周期)。
遗产
当您开始对象子类时,突变和定居者的真正潜力变得最明显,并且您可以利用现有的验证或设置代码,只需添加小额外的零件。
例如,您可能希望子类将与超类返回相同的结果,但大写而不是较低:
defgetName.(自己):返回极好的。getName.()。上()
或者您可能希望创建一个记录其操作的子类。
-(nsstring.*)名称{nsstring.*tmpname.=[极好的名称];nslog.(@“%@:设置名称到%@。”那自己那tmpname.);返回tmpname.;}
或者,您可以向变异子添加额外的验证:
defsetname.(自己那新名字):如果新名字。包含(你“mclovin”):增加TopicalButPRIDICTERABLEEXCEPTION.那“一个好的尝试,但......”返回极好的。setname.(新名字)
其中一些用途比其他用词更少,但它们在一起形成了对写作访问器和突变者的做法的强烈论证,超出了直接访问对象成员的最简单的防御,将绑定到实施细节的代码,并通过任何层次突破崩溃抽象。
我是估计的受访者和突变者吗?它们是否只有像客观的C,Java或C ++这样的rufty旧语言只有价值,而是浪费于今天的动态脚本Utoptias?我知道我曾经对他们感到沮丧,但随着我项目的规模和复杂性增加,我发现很难忽视他们的乐于乐于助人。