
【重构代码设计思想】
文章平均质量分 73
用架构的思想设计代码的结构,让程序中每个组件组装更合理。
Bruce小鬼
**高级测试开发**
- 技术是在不断打磨中成长,
- 能力是在不断采坑中成熟,
- 技术人的路就是在采坑中寻找乐趣,在成长过程中不断成熟。
> 书山有路勤为径,学海无涯苦作舟
关注:brucelong.blog.csdn.net
展开
-
重构类关系-Replace Inheritance with Delegation以委托取代继承十一
某个子类只使用超类接口中的一部分,或是根本不需要继承而来的数据。在子类中新建一个字段用以保存超类;调整子类函数,令它改而委托超类;然后去掉两者之间的继承关系。继承是个好东西,但有时候它并不是你要的。你常常会遇到这样的情况:一开始继承了一个类,随后发现超类中的许多操作并不真正适用于子类。这种情况下,你所拥有的接口并未真正反映出子类的功能。或者,你可能发现你从超类中继承了一大堆子类并不需要的数据,抑或你可能发现超类中的某些protected函数对子类并没有什么意义。原创 2023-03-27 10:17:31 · 1580 阅读 · 0 评论 -
重构类关系-Form Template Method塑造模板函数十
你有一些子类,其中相应的某些函数以相同顺序执行类似的操作,但各个操作的细节上有所不同。将这些操作分别放进独立函数中,并保持它们都有相同的签名,于是原函数也就变得相同了。然后将原函数上移至超类。继承是避免重复行为的一个强大工具。无论何时,只要你看见两个子类之中有类似的函数,就可以把它们提升到超类。但是如果这些函数并不完全相同该怎么办?我们仍有必要尽量避免重复,但又必须保持这些函数之间的实质差异。常见的一种情况是:两个函数以相同顺序执行大致相近的操作,但是各操作不完全相同。原创 2023-03-27 10:07:16 · 1154 阅读 · 0 评论 -
重构类关系-Collapse Hierarchy折叠继承关系九
超类和子类之间无太大区别。将它们合为一体如果你曾经编写过继承体系,就会知道,继承体系很容易变得过分复杂。所谓重构继承体系,往往是将函数和字段在体系中上下移动。完成这些动作后,你很可能发现某个子类并未带来该有的价值,因此需要把超类与子类合并起来。原创 2023-03-27 09:58:30 · 1120 阅读 · 0 评论 -
重构类关系-Extract Interface提炼接口八
若干客户使用类接口中的同一子集,或者两个类的接口有部分相同。将相同的子集提炼到一个独立接口中。类之间彼此互用的方式有若干种。“使用一个类”通常意味用到该类的所有责任区。另一种情况是,某一组客户只使用类责任区中的一个特定子集。再一种情况则是,这个类需要与所有协助处理某些特定请求的类合作。对于后两种情况,将真正用到的这部分责任分离出来通常很有意义,因为这样可以使系统的用法更清晰,同时也更容易看清系统的责任划分。如果新的类需要支持上述子集,也比较能够看清子集内有些什么东西。原创 2023-03-27 09:52:02 · 1718 阅读 · 0 评论 -
重构类关系-Extract Superclass提炼超类七
两个类有相似特性。为这两个类建立一个超类,将相同特性移至超类。重复代码是系统中最糟糕的东西之一。如果你在不同地方做同一件事情,一旦需要修改那些动作,你就得平白做更多的修改。重复代码的某种形式就是:两个类以相同的方式做类似的事情,或者以不同的方式做类似的事情。对象提供了一种简化这种情况的机制,那就是继承。但是,在建立这些具有共通性的类之前,你往往无法发现这样的共通性,因此经常会在具有共通性的类出现之后,再开始建立其间的继承结构。另一种选择就是Extract Class (149)。原创 2023-03-24 17:31:50 · 1149 阅读 · 0 评论 -
重构类关系-Extract Subclass提炼子类六
类中的某些特性只被某些(而非全部)实例用到。新建一个子类,将上面所说的那一部分特性移到子类中使用Extract Subclass (330)的主要动机是:你发现类中的某些行为只被一部分实例用到,其他实例不需要它们。有时候这种行为上的差异是通过类型码区分的,此时你可以使用Replace Type Code with Subclasses (223)或Replace Type Code with State/Strategy (227)。但是,并非一定要出现了类型码才表示需要考虑使用子类。原创 2023-03-24 16:55:35 · 1124 阅读 · 0 评论 -
重构类关系-Push Down Field字段下移五
超类中的某个字段只被部分(而非全部)子类用到。将这个字段移到需要它的那些子类去。原创 2023-03-24 16:31:57 · 1044 阅读 · 0 评论 -
重构类关系-Push Down Method函数下移四
超类中的某个函数只与部分(而非全部)子类有关。将这个函数移到相关的那些子类去。Push Down Method (328)与Pull Up Method (322)恰恰相反。当我有必要把某些行为从超类移至特定的子类时,我就使用Push Down Method (328),它通常也只在这种时候有用。使用Extract Subclass (330)之后你可能会需要它。原创 2023-03-24 14:40:23 · 1156 阅读 · 0 评论 -
重构类关系-Pull Up Constructor Body构造函数本体上移三
你在各个子类中拥有一些构造函数,它们的本体几乎完全一致。在超类中新建一个构造函数,并在子类构造函数中调用它。构造函数是很奇妙的东西。它们不是普通函数,使用它们比使用普通函数受到更多的限制。如果你看见各个子类中的函数有共同行为,第一个念头应该是将共同行为提炼到一个独立函数中,然后将这个函数提升到超类。对构造函数而言,它们彼此的共同行为往往就是“对象的建构”。这时候你需要在超类中提供一个构造函数,然后让子类都来调用它。很多时候,子类构造函数的唯一动作就是调用超类构造函数。原创 2023-03-24 14:32:43 · 1182 阅读 · 0 评论 -
重构类关系-Pull Up Method函数上移二
有些函数,在各个子类中产生完全相同的结果。将该函数移至超类。避免行为重复是很重要的。尽管重复的两个函数也可以各自工作得很好,但重复自身只会成为错误的滋生地,此外别无价值。无论何时,只要系统之内出现重复,你就会面临“修改其中一个却未能修改另一个”的风险。通常,找出重复也有一定困难。如果某个函数在各子类中的函数体都相同(它们很可能是通过复制粘贴得到的),这就是最显而易见的Pull Up Method (322)适用场合。当然,情况并不总是如此明显。原创 2023-03-24 12:08:20 · 1232 阅读 · 0 评论 -
重构类关系-Pull Up Field字段上移一
两个子类拥有相同的字段。将该字段移至超类如果各子类是分别开发的,或者是在重构过程中组合起来的,你常会发现它们拥有重复特性,特别是字段更容易重复。这样的字段有时拥有近似的名字,但也并非绝对如此。判断若干字段是否重复,唯一的办法就是观察函数如何使用它们。如果它们被使用的方式很相似,你就可以将它们归纳到超类去。本项重构从两方面减少重复:首先它去除了重复的数据声明;其次它使你可以将使用该字段的行为从子类移至超类,从而去除重复的行为。原创 2023-03-24 11:53:35 · 1152 阅读 · 0 评论 -
重构函数调用-Replace Exception with Test以测试取代异常十五
面对一个调用者可以预先检查的条件,你抛出了一个异常。修改调用者,使它在调用函数之前先做检查异常的出现是程序语言的一大进步。运用Replace Error Code with Exception (310),异常便可协助我们避免很多复杂的错误处理逻辑。但是,就像许多好东西一样,异常也会被滥用,从而变得不再让人愉快(就连味道极好的Aventinus啤酒,喝得太多也会让我厌烦[Jackson])。“异常”只应该被用于异常的、罕见的行为,也就是那些产生意料之外的错误的行为,而不应该成为条件检查的替代品。原创 2023-03-24 11:12:25 · 1182 阅读 · 0 评论 -
重构函数调用-Replace Error Code with Exception用异常取代错误码十四
某个函数返回一个特定的代码,用以表示某种错误情况。改用异常。和生活一样,计算机偶尔也会出错。一旦事情出错,你就需要有些对策。最简单的情况下,你可以停止程序运行,返回一个错误码。这就好像因为错过一班飞机而自杀一样(如果真那么做,哪怕我是只猫,我的九条命也早赔光了)。尽管我的油腔滑调企图带来一点幽默,但这种“软件自杀”选择的确是有好处的。如果程序崩溃代价很小,用户又足够宽容,那么就放心终止程序的运行好了。但如果你的程序比较重要,就需要以更认真的方式来处理。原创 2023-03-24 11:01:54 · 1379 阅读 · 0 评论 -
重构函数调用-Encapsulate Downcast封装向下转型十三
某个函数返回的对象,需要由函数调用者执行向下转型(downcast)。将向下转型动作移到函数中。在强类型OO语言中,向下转型是最烦人的事情之一。之所以很烦人,是因为从感觉上来说它完全没有必要:你竟然越俎代庖地告诉编译器某些应该由编译器自己计算出来的东西。但是,由于计算对象类型往往比较麻烦,你还是常常需要亲自告诉编译器对象的确切类型。向下转型在Java特别盛行,因为Java没有模板机制,因此如果你想从集合之中取出一个对象,就必须进行向下转型。向下转型也许是一种无法避免的罪恶,但你仍然应该尽可能少做。原创 2023-03-24 10:34:11 · 1074 阅读 · 0 评论 -
重构函数-Replace Constructor with Factory Method以工厂函数取代构造函数十二
你希望在创建对象时不仅仅是做简单的建构动作。将构造函数替换为工厂函数。使用Replace Constructor with Factory Method (304)的最显而易见的动机,就是在派生子类的过程中以工厂函数取代类型码。你可能常常需要根据类型码创建相应的对象,现在,创建名单中还得加上子类,那些子类也是根据类型码来创建。然而由于构造函数只能返回单一类型的对象,因此你需要将构造函数替换为工厂函数[Gang of Four]。此外,如果构造函数的功能不能满足你的需要,也可以使用工厂函数来代替它。原创 2023-03-24 10:14:47 · 1124 阅读 · 0 评论 -
重构函数调用-Hide Method隐藏函数十一
有一个函数,从来没有被其他任何类用到。将这个函数修改为private。重构往往促使你修改函数的可见度。提高函数可见度的情况很容易想象:另一个类需要用到某个函数,因此你必须提高该函数的可见度。但是要指出一个函数的可见度是否过高,就稍微困难一些。理想状况下,你可以使用工具检查所有函数,指出可被隐藏起来的函数。即使没有这样的工具,你也应该时常进行这样的检查。一种特别常见的情况是:当你面对一个过于丰富、提供了过多行为的接口时,就值得将非必要的取值函数和设值函数隐藏起来。原创 2023-03-24 09:55:31 · 1261 阅读 · 0 评论 -
重构函数调用-Remove Setting Method移除设置函数十
类中的某个字段应该在对象创建时被设值,然后就不再改变。去掉该字段的所有设值函数。如果你为某个字段提供了设值函数,这就暗示这个字段值可以被改变。如果你不希望在对象创建之后此字段还有机会被改变,那就不要为它提供设值函数(同时将该字段设为final)。这样你的意图会更加清晰,并且可以排除其值被修改的可能性——这种可能性往往是非常大的。如果你保留了间接访问变量的方法,就可能经常有程序员盲目使用它们[Beck]。这些人甚至会在构造函数中使用设值函数!原创 2023-03-24 09:43:38 · 331 阅读 · 0 评论 -
重构函数调用-Introduce Parameter Object引入参数对象九
某些参数总是很自然地同时出现。以一个对象取代这些参数你常会看到特定的一组参数总是一起被传递。可能有好几个函数都使用这一组参数,这些函数可能隶属同一个类,也可能隶属不同的类。这样一组参数就是所谓的Data Clumps(数据泥团),我们可以运用一个对象包装所有这些数据,再以该对象取代它们。哪怕只是为了把这些数据组织在一起,这样做也是值得的。本项重构的价值在于缩短参数列,而你知道,过长的参数列总是难以理解的。此外,新对象所定义的访问函数还可以使代码更具一致性,这又进一步降低了理解和修改代码的难度。原创 2023-03-23 17:05:56 · 725 阅读 · 0 评论 -
重构函数调用-Replace Parameter with Method以函数取代参数八
对象调用某个函数,并将所得结果作为参数,传递给另一个函数。而接受该参数的函数本身也能够调用前一个函数。让参数接受者去除该项参数,并直接调用前一个函数。如果函数可以通过其他途径获得参数值,那么它就不应该通过参数取得该值。过长的参数列会增加程序阅读者的理解难度,因此我们应该尽可能缩短参数列的长度。缩减参数列的办法之一就是:看看参数接受端是否可以通过与调用端相同的计算来取得参数值。原创 2023-03-23 16:39:53 · 523 阅读 · 0 评论 -
重构函数调用-Preserve Whole Object保持对象完整七
你从某个对象中取出若干值,将它们作为某一次函数调用时的参数。改为传递整个对象。有时候,你会将来自同一对象的若干项数据作为参数,传递给某个函数。这样做的问题在于:万一将来被调用函数需要新的数据项,你就必须查找并修改对此函数的所有调用。如果你把这些数据所属的整个对象传给函数,可以避免这种尴尬的处境,因为被调用函数可以向那个参数对象请求任何它想要的信息。除了可以使参数列更稳固之外,Preserve Whole Object (288)往往还能提高代码的可读性。原创 2023-03-23 16:20:04 · 405 阅读 · 0 评论 -
重构函数调用-Replace Parameter with Explicit Methods以明确函数取代参数六
你有一个函数,其中完全取决于参数值而采取不同行为。针对该参数的每一个可能值,建立一个独立函数Replace Parameter with Explicit Methods (285)恰恰相反于Parameterize Method (283)。如果某个参数有多种可能的值,这个值的数量是有限的,内容可以预知的。而函数内又以条件表达式检查这些值,并根据不同参数值做出不同的,那么就应该使用本项重构提供不同的函数给调用者使用,就可以避免出现条件表达式。原创 2023-03-23 14:26:38 · 640 阅读 · 0 评论 -
重构函数调用-Parameterize Method令函数携带参数五
若干函数做了类似的工作,但在函数本体中却包含了不同的值。建立单一函数,以参数表达那些不同的值。你可能会发现这样的两个函数:它们做着类似的工作,但因少数几个值致使行为略有不同。在这种情况下,你可以将这些各自分离的函数统一起来,并通过参数来处理那些变化情况,用以简化问题。这样的修改可以去除重复的代码,并提高灵活性,因为你可以用这个参数处理更多的变化情况。原创 2023-03-23 14:04:37 · 245 阅读 · 0 评论 -
重构函数调用-Separate Query from Modifier将查询函数和修改函数分离四
某个函数既返回对象状态值,又修改对象状态。建立两个不同的函数,其中一个负责查询,另一个负责修改。原创 2023-03-23 11:56:40 · 332 阅读 · 0 评论 -
重构函数调用-Remove Parameter移除参数三
函数本体不再需要某个参数。将该参数去除程序员可能经常添加参数,却往往不愿意去掉它们。他们打的如意算盘是:无论如何,多余的参数不会引起任何问题,而且以后还可能用上它。这也是恶魔的诱惑,一定要把它从脑子里赶出去!参数代表着函数所需的信息,不同的参数值有不同的意义。函数调用者必须为每一个参数操心该传什么东西进去。如果你不去掉多余参数,就是让你的每一位用户多费一份心。是很不划算的,更何况“去除参数”是非常简单的一项重构。原创 2023-03-23 11:46:52 · 429 阅读 · 0 评论 -
重构函数调用-Add Parameter添加参数二
某个函数需要从调用端得到更多信息。为此函数添加一个对象参数,让该对象带进函数所需信息。Add Parameter (275)是一个很常用的重构手法,我几乎可以肯定你已经用过它了。使用这项重构的动机很简单:你必须修改一个函数,而修改后的函数需要一些过去没有的信息,因此你需要给该函数添加一个参数。实际上我比较需要说明的是:不使用本重构的时机。除了添加参数外,你常常还有其他选择。只要可能,其他选择都比添加参数要好,因为它们不会增加参数列的长度。原创 2023-03-23 11:33:19 · 766 阅读 · 0 评论 -
重构函数调用-Rename Method重新命名函数一
函数的名称未能揭示函数的用途。修改函数名称。我极力提倡的一种编程风格就是:将复杂的处理过程分解成小函数。但是,如果做得不好,这会使你费尽周折却弄不清楚这些小函数各自的用途。要避免这种麻烦,关键就在于给函数起一个好名称。函数的名称应该准确表达它的用途。给函数命名有一个好办法:首先考虑应该给这个函数写上一句怎样的注释,然后想办法将注释变成函数名称。你常常无法第一次就给函数起一个好名称。这时候你可能会想:就这样将就着吧,毕竟只是一个名称而已。当心!这是恶魔的召唤,是通向混乱之路,千万不要被它诱惑!原创 2023-03-23 11:08:56 · 785 阅读 · 0 评论 -
重构条件-Introduce Assertion引入断言八
某一段代码需要对程序状态做出某种假设。以断言明确表现这种假设常常会有这样一段代码:只有当某个条件为真时,该段代码才能正常运行。例如平方根计算只对正值才能进行,又例如某个对象可能假设其字段至少有一个不等于null。这样的假设通常并没有在代码中明确表现出来,你必须阅读整个算法才能看出。有时程序员会以注释写出这样的假设。而我要介绍的是一种更好的技术:使用断言明确标明这些假设。断言是一个条件表达式,应该总是为真。如果它失败,表示程序员犯了错误。原创 2023-03-23 10:47:21 · 485 阅读 · 0 评论 -
重构条件-Introduce Null Object引入Null 对象七
你需要再三检查某对象是否为null。将null值替换为null对象。多态的最根本好处在于:你不必再向对象询问“你是什么类型”而后根据得到的答案调用对象的某个行为——你只管调用该行为就是了,其他的一切多态机制会为你安排妥当。当某个字段内容是null 时,多态可扮演另一个较不直观(亦较不为人所知)的用途。让我们先听听Ron Jeffries的故事。摘录来自: [美]马丁·福勒(Martin Fowler). “重构:改善既有代码的设计。原创 2023-03-23 10:39:37 · 652 阅读 · 0 评论 -
重构条件-Replace Conditional with Polymorphism以多态取代条件式六
你手上有个条件表达式,它根据对象类型的不同而选择不同的行为。将这个条件表达式的每个分支放进一个子类内的覆写函数中,然后将原始函数声明为抽象函数。在面向对象术语中,听上去最高贵的词非“多态”莫属。多态最根本的好处就是:如果你需要根据对象的不同类型而采取不同的行为,多态使你不必编写明显的条件表达式。正因为有了多态,所以你会发现:“类型码的switch语句”以及“基于类型名称的if-then-else语句”在面向对象程序中很少出现。多态能够给你带来很多好处。原创 2023-03-23 09:58:08 · 434 阅读 · 0 评论 -
重构条件-Replace Nested Conditional with Guard Clauses以卫语句取代嵌套条件式五
函数中的条件逻辑使人难以看清正常的执行路径。使用卫语句表现所有特殊情况根据我的经验,条件式通常有两种呈现形式。第一种形式是:所有分支都属于正常行为。第二种形式则是:条件式提供的答案中只有一种是正常行为,其他都是不常见的情况。这两类条件式有不同的用途,这一点应该通过代码表现出来。如果两条分支都是正常行为,就应该使用形如「if…then…」的条件式;如果某个条件极其罕见,就应该单独检查该条件,并在该条件为真时立刻从函数中返回。这样的单独检查常常被称为。原创 2023-03-22 17:25:09 · 359 阅读 · 0 评论 -
重构条件-Remove Control Flag移除控制标记四
在一系列布尔表达式中,某个变量带有“控制标记”(control flag)的作用。以break语句或return语句取代控制标记。在一系列条件表达式中,你常常会看到用以判断何时停止条件检查的控制标记这样的控制标记带来的麻烦超过了它所带来的便利。人们之所以会使用这样的控制标记,因为结构化编程原则告诉他们:每个子程序只能有一个入口和一个出口。我赞同“单一入口”原则(而且现代编程语言也强迫我们这样做),但是“单一出口”原则会让你在代码中加入讨厌的控制标记,大大降低条件表达式的可读性。原创 2023-03-22 16:39:44 · 476 阅读 · 0 评论 -
重构条件-Consolidate Duplicate Conditional Fragments合并重复的条件片段三
在条件表达式的每个分支上有着相同的一段代码。将这段重复代码搬移到条件表达式之外。有时你会发现,一组条件表达式的所有分支都执行了相同的某段代码。如果是这样,你就应该将这段代码搬移到条件表达式外面。这样,代码才能更清楚地表明哪些东西随条件的变化而变化、哪些东西保持不变。原创 2023-03-22 16:21:32 · 356 阅读 · 0 评论 -
重构条件-Consolidate Conditional Expression合并条件式二
你有一系列条件测试,都得到相同结果。将这些测试合并为一个条件表达式,并将这个条件表达式提炼成为一个独立函数。有时你会发现这样一串条件检查:检查条件各不相同,最终行为却一致。如果发现这种情况,就应该使用“逻辑或”和“逻辑与”将它们合并为一个条件表达式。之所以要合并条件代码,有两个重要原因。首先,合并后的条件代码会告诉你“实际上只有一次条件检查,只不过有多个并列条件需要检查而已”,从而使这一次检查的用意更清晰。原创 2023-03-22 16:04:48 · 483 阅读 · 0 评论 -
重构条件-Decompose Conditional分解条件式一
你有一个复杂的条件(if-then-else)语句。从if、then、else三个段落中分别提炼出独立函数程序之中,复杂的条件逻辑是最常导致复杂度上升的地点之一。你必须编写代码来检查不同的条件分支、根据不同的分支做不同的事,然后,你很快就会得到一个相当长的函数。大型函数自身就会使代码的可读性下降,而条件逻辑则会使代码更难阅读。在带有复杂条件逻辑的函数中,代码(包括检查条件分支的代码和真正实现功能的代码)会告诉你发生的事,但常常让你弄不清楚为什么会发生这样的事,这就说明代码的可读性的确大大降低了。原创 2023-03-22 15:48:36 · 539 阅读 · 0 评论 -
重构数据-Replace Subclass with Fields以字段取代子类十五
你的各个子类的唯一差别只在“返回常量数据”的函数身上。修改这些函数,使它们返回超类中的某个(新增)字段,然后销毁子类。建立子类的目的,是为了增加新特性或变化其行为。有一种变化行为被称为“常量函数”(constant method)[Beck],它们会返回一个硬编码的值。这东西有其用途:你可以让不同的子类中的同一个访问函数返回不同的值。你可以在超类中将访问函数声明为抽象函数,并在不同的子类中让它返回不同的值。尽管常量函数有其用途,但若子类中只有常量函数,实在没有足够的存在价值。原创 2023-03-22 15:23:41 · 377 阅读 · 0 评论 -
重构数据-State/strategy 取代类型码十四
你有一个类型码,它会影响类的行为,但你无法通过继承手法消除它。以状态对象取代类型码。本项重构和Replace Type Code with Subclasses (223)很相似,但如果“类型码的值在对象生命期中发生变化”或“其他原因使得宿主类不能被继承”,你也可以使用本重构。本重构使用State模式或Strategy模式[Gang of Four]。State模式和Strategy模式非常相似,因此无论你选择其中哪一个,重构过程都是相同的。原创 2023-03-22 14:52:49 · 310 阅读 · 0 评论 -
重构数据-Replace Type Code with Subclasses以子类取代类型码十三
在类中有一个变量名称,它用来代表不同的类型,不同的类型改变了类不同的行为,以子类取代这个变量。如果你面对的类型码(变量)不会影响宿主类的行为,可以使用Replace Type Code with Class (218)来处理它们。但如果类型码会影响宿主类的行为,那么最好的办法就是借助多态来处理变化行为。一般来说,这种情况的标志就是像switch这样的条件表达式。这种条件表达式可能有两种表现形式:switch语句或者if-then-else结构。原创 2023-03-20 16:31:39 · 492 阅读 · 0 评论 -
重构数据-Replace Type Code with Class以类取代类型码十二
类之中有一个数值类型码,但它并不影响类的行为。以一个新的类替换该数值类型码在以C为基础的编程语言中,类型码或枚举值很常见。如果带着一个有意义的符号名,类型码的可读性还是不错的。问题在于,符号名终究只是个别名,编译器看见的、进行类型检验的,还是背后那个数值。任何接受类型码作为参数的函数,所期望的实际上是一个数值,无法强制使用符号名。这会大大降低代码的可读性,从而成为bug之源。如果把那样的数值换成一个类,编译器就可以对这个类进行类型检验。原创 2023-03-20 15:39:17 · 485 阅读 · 0 评论 -
重构数据-Encapsulate Collection封装集合十
有个函数返回一个集合。让这个函数返回该集合的一个只读副本,并在这个类中提供添加/移除集合元素的函数。我们常常会在一个类中使用集合(collection,可能是array、list、set或vector)来保存一组实例。这样的类通常也会提供针对该集合的取值/设值函数。但是,集合的处理方式应该和其他种类的数据略有不同。取值函数不该返回集合自身,因为这会让用户得以修改集合内容而集合拥有者却一无所悉。这也会对用户暴露过多对象内部数据结构的信息。原创 2023-03-20 14:43:02 · 435 阅读 · 0 评论 -
重构数据-Encapsulate Field封装值域九
将数据封装为私有,防止其他对象修改数据。面向对象的首要原则之一就是封装(encapsulation),或者称为「数据隐藏」(data hidding)。按此原则,你绝不应该将数据声明为public,否则其他对象就有可能访问甚至修改这项数据,而拥有该数据的对象却毫无察觉。public 数据被看做是一种不好的作法,因为这样会降低程序的模块化程度(modularity)。原创 2023-03-20 11:43:34 · 437 阅读 · 0 评论