欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

[读书笔记] 代码整洁之道(四): 类

程序员文章站 2022-04-26 23:30:43
...

第十章 类

  1. 类的组织

    类的编写因符合自顶向下原则,从一组变量列表开始:public static的常量,然后private static 变量,以及private 变量。变量列表之后是公共函数,然后公共函数调用的私有工具函数紧随其后。
    封装:保持变量和工具函数的私有性。

  2. 类应该短小

    跟函数一样,类的首要规则是要更短小。
    对于函数我们可以通过行数来衡量大小。对于类,我们通过权责来衡量。
    类的名称应该描述其权责。

    单一权责原则SRP:类或模块应且只有一条加以修改的理由。鉴别权责(修改理由)可以帮助我们在代码中认识并创建出更好的抽象。系统应该由许多短小的类而不是少量巨大的类组成。每个小类封装一个权责,只有一个修改的原因,并于少数其他类仪器协同达成期望的系统行为。

    内聚:类应该只有少量的实体变量。类中每个方法都应该操作一个或多个这种实体变量。通常而言,方法操作的变量越多,内聚性越大。内聚性高,意味着类中的方法和变量互相依赖、互相组合成一个逻辑整体。

    保持内聚性就会得到许多短小的类:因为将大函数切割为小函数,那么意味着一些函数的私有变量要进行传递,比较简便的方法就是将这些私有变量提升为实体变量,这样不要传递变量就能拆分函数。但是这样就会导致类丧失内聚性,因为多了很多只允许少量函数共享而存在的实体变量。既然有些函数需要共享某些变量,那就应该让它们拥有自己的类,所以当类丧失了内聚性,就拆分,这样程序就会更加由组织,结构更加透明。

  3. 为了修改而组织

    一般系统大多会一直持续修改,如果类组织的不好,会导致每次修改都会影响到其他部分的风险。
    这个例子是一个必须打开修改的类:

     public class Sql {
         public Sql(String table, Column[] columns)
         public String create()
         public String insert(Object[] fields)
         public String selectAll()
         public String findByKey(String keyColumn, String keyValue)
         public String select(Column column, String pattern)
         public String select(Criteria criteria)
         public String preparedInsert()
    
         private String columnList(Column[] columns)
         private String valuesList(Object[] fields, final Column[] columns) 
         private String selectWithCriteria(String criteria)
         private String placeholderList(Column[] columns)
     }

    当要添加新语句类型时,就要修改Sql类。改动单个语句类型时,也要进行修改。所以很显然的违反了SRP原则。

    修改:将Sql类的每个接口方法都重构到从Sql类派生出来的类中了。私有方法如valueList,直接移到需要用他们的地方。公共私有行为被划分到独立的两个工具类。

     abstract class Sql {
         public Sql(String table, Column[] columns) 
         abstract public String generate();
     }
     class CreateSql extends Sql {
         public CreateSql(String table, Column[] columns) 
         @Override 
         public String generate(){};
     }
     class SelectSql extends Sql {
         public SelectSql(String table, Column[] columns) 
         @Override 
         public String generate(){};
     }
     class InsertSql extends Sql {
         public InsertSql(String table, Column[] columns, Object[] fields) 
         @Override
         public String generate(){};
         private String valuesList(Object[] fields, final Column[] columns){};
     }
     class SelectWithCriteriaSql extends Sql { 
         public SelectWithCriteriaSql(String table, Column[] columns, Criteria criteria) 
         @Override 
         public String generate(){};
     }
     class SelectWithMatchSql extends Sql { 
         public SelectWithMatchSql(String table, Column[] columns, Column column, String pattern) 
         @Override           
         public String generate(){};
     }
     class FindByKeySql extends Sql {
         public FindByKeySql(String table, Column[] columns, String keyColumn, String keyValue) 
         @Override           
         public String generate(){};
     }
     class PreparedInsertSql extends Sql {
         public PreparedInsertSql(String table, Column[] columns) 
         @Override 
         public String generate() {};
         private String placeholderList(Column[] columns)
     }
     class Where {
         public Where(String criteria) public String generate()
     }
     class ColumnList {
         public ColumnList(Column[] columns) public String generate()
     }

    这样需要添加update语句时,现存类不需要修改,直接添加Sql子类UpdateSql。经过修改,Sql支持SRP,支持OCP开放闭合原则:类应当对扩展开放,对修改封闭

    隔离修改
    具体类包含实现细节(代码),而抽象类则只呈现概念。依赖于具体细节的客户类,当细节改变时,就会有风险。我们可以借助接口和抽象类来隔离这些细节带来的影响依赖倒置原则DIP:认为类应该依赖于抽象而不是依赖于具体细节。