代码大全学习笔记3

第六章

6.2良好的类接口

好的抽象

  1. 好的抽象类或者说结构化编程,类或者结构中的操作只是针对类本身或结构本身的操作,同时这些操作不需要类或者结构的使用者了解内部的实现方式;
  2. 设计类或者结构的时候,内聚性(功能结构尽量简单或者实现的方式简单一点,尤其是不能让调用者无法理解多功能之间的相关性)最好高一点,如果由于功能过于复杂且相关性很差,那么可以将不同的功能进行类或结构化处理;
  3. 对类抽象的评估,就是评估类提供的接口函数是否能明确完整体现抽象类的功能和,或者说对于应用者而言,这些接口是否是语义明确、使用简单并能自由控制类或者结构的;
  4. 类接口的指导定义:
    类的接口应该展现一致的抽象层次:没个类就应该实现一个ADT(抽象数据类型),且仅实现这个ADT;混杂的抽象会让程序越来越难以理解,以至于整个程序堕落到无法维护的地步;
    一定要理解类所实现的抽象是什么:当你无法正确理解抽象的本质的时候,你就无法写出清晰正确简洁完全的接口,并且也无法正确的隐藏信息,那么你在后期维护的时候就会添加一些没有意义的工作量;
    提供成对的服务:大多数的操作都需要与其对应的、相等以及相反的操作,因此在设计类或者结构的时候,要仔细的考虑是否需要这种对应性的操作;
    把不相关的数据转移到其他类中:当一个类的数据(也就是我所理解的属性)被泾渭分明地分成两部分的时候,就要考虑一下是否可以抽象为两个类;(其实,这个工作应该更多在迭代中去注意)
    尽量让接口可编程,而不是表达语义:每个接口都应该包括可编程部分(代码)和语义部分(注释)组成,这一条指导的意思就是虽然注释能够起到使用说明的作用,但是为了能够保证程序的执行和避免应用者的误操作,那么应该在程序实现上就体现出注释中的一些条件等问题;
    谨防在修改时破坏接口的抽象
    c++语言示例:在维护时被破坏的类接口
    class Employee{
    public:

    //pubulic routines
    FullName GetName() const;
    Address GetAddress() const;
    PhoneNumber GetWorkPhoneNumber() const;

    bool IsJobClassificationValid(JobClassification jobClass);
    bool IsZipCodeValid( Address address );
    bool IsPhoneNumberValid( PhoneNumber phoneNumber );
    SqlQuery GetQueryToCreateNewEmployee() const;
    SqlQuery GetQueryToModifyEmployee() const;
    SqlQuery GetQueryToRetrieveEmployee() const;

    private:

    };
    在雇工和检查邮政代码、电话号码或职位的子程序之间不存在什么逻辑上的相关性,那么暴露SQL语句查询细节的子程序所处的抽象层次比Employee类也要低得多,它们破坏了Employee类的抽象;
    不要添加与接口抽象不一致的公用成员:在向类中添加子程序的时候要谨慎,不能破坏抽象的完整性;
    同时考虑抽象性和内聚性:抽象性与内聚性是相辅相成的,抽象性更有助于深入理解类的设计,当内聚性不好的时候,你可以从抽象性这个方面进行考虑来提高程序的内聚性;

良好的封装

——抽象通过提供一个可以让你忽略实现细节的模型来管理复杂度,而封装则强制阻止你看到细节(我的理解就是封装是抽象的一种实现手段)

  1. 尽可能地限制类和成员的可访问性:让可访问性尽可能低是促成封装的原则之一,不知道如何做的情况下,多隐藏要比少隐藏好;
  2. 不要公开暴露成员数据:暴露成员数据会破坏封装性,从而限制你对这个抽象的封装能力,如类暴露成员的话,就无法预知成员是何时被修改的已经如何修改的,而如果类通过成员函数获取数据的话,那么就能很好的控制数据何时被修改如何被修改,同时也便于程序修改维护;
  3. 避免把私用的实现细节放入类的接口中
    在这里插入图片描述在这里插入图片描述其实我对于这两张图片有一点疑问,就是第二张图片虽然将数据进行了封装了,但是你这个EmployeeImplementation结构体或者类的定义不照样也得向调用者开放吗?如果开发的话,不就是一样的效果吗?唯一的区别就是调用者看到这个类的时候不知道,private中封装的是什么,如果调用者想深入了解一下的话,那么就很明显的能了解到这个private的封装和定义;
  4. 不要对类的使用作任何假设
  5. 避免使用友元类:正确的友元类会有助于管理复杂度,但一般情况下,友元类会破坏封装性,因为它让你在同一时刻需要考虑更多的代码量,从而增加复杂度;
  6. 不要因为一个子程序仅使用公用子程序接口,就把它归为公开接口:是否设置为公开接口的条件是是否符合ADT的抽象;
  7. 让阅读代码比编写代码更方便:为了让编写代码更方便而降低可读性是非常不经济的;
  8. 要格外警惕从语义上破坏封装性:对于调用者而言,只需要看接口函数就能理解对类的操作,而不是需要了解内部实现;当有调用者不能理解类的接口操作的时候,不是给他看源代码或者解释原理,而是修改接口和说明(即在代码层修改,这样修改有记录,而且调用者不能正确理解就说明代码在封装和抽象方面存在问题,因此也需要修改代码);
  9. 留意过于耦合的紧密关系:类之间的联系越松越好,可以采用的手段如下:
    尽可能地限制类和成员的可访问性;
    避免友元类,因为它们之间是紧耦合的;
    在基类中把数据声明为private而不是protected,以降低派生类和基类之间耦合的程度;
    避免在类的公开接口中暴露成员数据;
    要对语义上破坏封装性保持警惕;
    觉察“Demeter(德墨忒耳)法则”;

猜你喜欢

转载自blog.csdn.net/u012850592/article/details/89431196
今日推荐