美文网首页
设计坏味道

设计坏味道

作者: 程序猿春天 | 来源:发表于2019-06-25 22:38 被阅读0次

    设计坏味道

    1.  设计坏味道概述

    为何要关注坏味道,因为坏味道影响了软件的质量;给项目的开发、维护、扩展等带来了影响;

    A.    软件质量

                  i.        可理解性

    1.    代码理解的难易程度;

                ii.        可以修改性

    1.    修改代码时,不会导致连锁反应;

                iii.        可扩展性

    1.    增加新功能,不会导致连锁反应;

                iv.        可重用性

    1.    代码可以在相同问题域中,直接复用;

                v.        可测试性

    1.    支持单元测试

                vi.        可靠性

    1.    正确实现功能情况下,支持容错性;                                   

    2.  坏味道分类

    3.  抽象性

    A.    缺失抽象

    Example:

    _ 问题点在JDK1.0中方法printStackTrace()以字符串的方式将栈跟踪打印到标准错误流:

          public classThrowabe{  public voidprintStackTrace();

          }

          在需要以编程方式访问栈跟踪元素的客户程序中,必须要编程代码来获取数据,如行号等,由于客户程度依赖这种字符串格式,JDK设计人员只能在后续版本中兼容这种格式了。

    _ 解决方法

          public classThrowabe{  public voidprintStackTrace(); public                                    StackTraceElement[]getStackTrace();

          }

    从Jdk1.4起对JAVA的API进行了改进,StackTraceElement类就是原来设计中缺失的对象,定义如下:

          public finalclassStackTraceElement{

              public final classStackTraceElement{

                public StringgetFilename();

              publicintgetLineNumber();

              public StringgetClassname();

                ......

                }

    Example:

    _ 问题点

      细粒度的异常处理问题,以前见过系统的异常类只是继承Exception,只保存了message信息;因此如果需要细分并根据不同类型,不同的级别急性控制时,就比较麻烦;

    _ 解决方法

    _ 细分异常类型

    _ 增加errorcode

    异常类包含了一个接口,具体异常类中,枚举类型实现该接口;

    说明:使用function编程解耦业务异常类的处理,使业务类只关注业务;

    B.    命令式抽像

    Example:

    _    问题点

        说明:每个类只包含一个方法,分别是:create、display、copy;因此存在命令式抽象,会增加类的数量、开发、维护的复杂度;而且把本该内聚的方法,分散到多个类上;没有做到内聚,而增加了耦合;

    _    解决方案

    根据高内聚原则,归并到一个类中;

    C.    不完整抽象

                    抽象未支持互补方法,导致不完成抽象,比如一个抽象接口,只有startUp,而没有stopUp方法;

    常见互补方法:

    D.    多方面抽象

                    对象被赋予不止一种职责,违背单一职责原则;

    Example:

    _  问题点

    java.util.Calendar

    类承担了多项职责,不仅提供了日期相关的功能,还提供了与时间有关的功能,存大多方面抽象。由于同时支持日期和时间的方法,Calendar类接口很大且难为理解,在JDK7中,java.util.Calendar类包括了2825行代码,有67个方法和71个字段。

    _  解决方案对于Calendar类,一种可能的重构是,将Calendar类与时间相关的功能提取到新类Time中,并将相关方法和字段移到新提取的类中,在Java8中引入了一些支持日期和时间的新类,这些类位于java.time中。

    E.    不必要抽象

    Example:

    _  问题点

    publicinterfaceWindowConstants{

    public static finalintDO_NOTHING_ON_CLOSE=0;

    public static finalintHIDE_ON_CLOSE=1;

    }

      注:这个接口是典型的常量接口javax.swing.WindowConstants,为啥用接口来存储常量,因为首先枚举是jdk1.5才引入的,其次通过接口中定义常量,可方便类通过继承而不是委托来使用它们,因为通过实现接口,类可方便的访问接口中的常量,为什么不使用类来存储常量呢,因为接口支持多继承。

    那么接口这样定义常量有哪些问题呢?

    A

    、派生类被无关的常量影响。

    B

    、这些常量属于实现细节,通过接口暴露它们违反封装原则。

    C

    、接口中存储常量,修改它们会影响其他使用者。

    _  解决方案将WindowsConstants定义为枚举,直接使用。

    F.    重复抽象

    根据DRY原则规定:对于每个技术点,系统中都只能有一个明确的表示。导致重复抽象的原因有:

    A

    、复制-粘贴编程手法

    B

    、即兴维护

    C

    、交流不畅

    Example1:

    _  问题点

    java.util.Date

    和其派生类java.sql.Date同名,这两个类位于不同的包中,编译器不会因为它们同名而报错,但这让使用者一头雾水,这样将导致二义性。

    _  解决方案将Date名称前面加上用途限定语,比如java.sql.SQLDate更合适。

    Example2:

          问题点

          相同的类,包名称不一样,不同的包面向不同的使用者;

    task-clent中包含com.xx.xx.task.domain.task.Task和task-server 中的com.xx.xx.task.domain.task.Task,一个抽象放到不同的模块,项目中最好也要避免这种情况;

                  i.        DRY原则

    用Lambda和Function解决方式:

    说明:在该execute基础上实现单、宽index的cud操作;

    G.    书籍推荐:

    <<软件设计重构>>

    4.  总结本次只分享抽象性的坏味道,欢迎感兴趣的同事,结合自己的理解和实践,继续分享其他模块;

    相关文章

      网友评论

          本文标题:设计坏味道

          本文链接:https://www.haomeiwen.com/subject/nlijnqtx.html