写点什么

设计模式 -- 正确学习姿势

用户头像
张荣召
关注
发布于: 2020 年 10 月 01 日

1 设计模式:

使用设计模式优化排序工具包的设计

    

1.1 什么是设计模式?

       每一种模式都描述了一种问题的通用解决方案。这种问题在我们的环境中,不停的重复出现。

       设计模式是一种可重复使用的解决方案。


典型的重复问题

<===设计模式(问题关注点,如何解决,优缺点,改进点)

<===通用解决方案。


1.2 设计模式学习方法:

1.设计模式解决什么问题?

2.设计模式如何解决问题?

3.设计模式解决过程中,体现的优势什么?如何改进?有没有更好的解决方案呢?

1.3 设计模式的四个组成部分:

1.模式的名称--表达设计

2.待解问题--描述了何时需要运用这种模式,以及运用模式的环境(上下文)

3.解决方案--描述了组成设计的元素(类和对象),他们的关系,职责以及合作,但是这种解决方案是抽象的,他不代表具体的实现。

4.结论--运用这种模式所带来的利弊。主要是指它对系统的弹性,扩展性和可移植性性的影响。

1.4 设计模式分类:

从功能分:

  • 创建模式(Creational Patterns)--对类的实例化过程的抽象。

  • 结构模式(Structural Patterns)--将类或者对象组合形成更大的结构。

  • 行为模式 (Behavioral Patterns)  --对在不同的对象之间划分职责和算法的抽象化。

从方式分:

  • 类模式-----以继承的方式实现模式,静态的。

  • 对象模式---以组合的方式实现模式,动态的。


2 案例分析:


设计排序工具包:

1.可以使用各种算法---------------Sorter(冒泡排序,快速排序,插入排序...)使用什么算法排序

2.可以对各种数据结构排序--------Sortable(Array,List.....)数据容器:数据存放到什么位置

3.可以对数据内容排序------------Comparator(integer....)数据内容:数据内容怎么比较


客户端使用:可以直接 new 一个具体的 Sorter。

问题:如果直接 new 一个具体的对象,则客户端程序直接与具体对象绑定,如果要使用不同的算法,则需要更新代码。 客户端需要调整代码,导致客户端的不稳定。====>违反 OCP 原则(开放关闭原则)。


改进目标:让客户端程序依赖抽象编程,不依赖具体类,即使更换具体的排序算法 Sorter(比如:快速排序), 客户端不需要更新代码,保持客户端程序的稳定。


2.1 改进方案一:工厂模式

遵循 OCP 设计原则,使用设计模式(简单工厂)指导:


代码:

public class SorterFactory{

       public static <T> Sorter<T> getSorter(){

              return new BubbleSorter<T>();//使用新的排序算法,这里不符合开闭原则。

       }

}


public class Client{ //符合开闭原则

      public static void main(String[] args){

           Integer[] array={5,4,9,7,6,3,8,1,0,2};

           Sorter<Integer> sorter=SorterFactory.getSorter();

           Sortable<Integer> sortable=SortableFactory.getSortable();

           Comparator<Integer> comparator=ComparatorFactory.getComparator();


          sorter.sort(sortable,comparator);

          ...

      }

}


改进评估:Client 符合 OCP 原则,更新算法时,Client 不需要更新代码,重新编译。

                 但是 SortFactory,如果使用新的算法时,需要更新 new 一个对象,

                 来更新代码==>导致 SortFactory 不符合 OCP 原则。

2.2 改进方案二:

改进 SortFactory 符合 OCP, 代码如下:

class SorterFactory_2{

      public static <T> Sorter<T> getSorter(String implClass){

            try{

                Class impl=Class.forName(implClass);

                return (Sorter<T>)impl.newInstance();       

           }catch(Exception e){

                throw new IllegalArgumentException("Illegal class name: "+implClass,e);

           }

      }

}


Sorter<Integer> sorter=SorterFactory_2.getSorter("demo.sort.impl.BubbleSorter");

改进评估:Sorter 排序算法的具体类名,当作字符串传递给工厂方法,工厂方法反射获取实例。

                 Sorter 如果需要新的算法,只需要传递类的完全限定名,不需要再修改程序本身。

                 ==>  SorterFactory 符合 OCP。但是,Client 需要传递算法的完全限定名。

优劣评估:=> 1.Client 代码需要修改,Client 又不符合 OCP;

                 => 2.丧失编译器的类型安全检查(Client 和 Factory 均不安全)

                 => 3.Client 任然知道 Sorter 的实现是什么

                 => 4.限制了 Sorter 的实现只能通过“默认构造函数”创建

2.3 改进方案三:

对 SortFactory 继续改进

class SorterFactory_3{

      private final static Properties IMPLS=loadImpls();

      private static Properties loadImpls(){

            Properties defaultImpls=new Properties();

            Properties impls=new Properties(defaultImpls);

            defaultImpls.setProperty("sorter","demo.sort.impl.BubbleSorter");

            try{

                  impls.load(SorterFactory_3.class.getResourceAsStream("sort.properties"));

            }catch(IOException e){

               throw new RuntimeException(e);

            }

            return impls;

      }


      public static <T> Sorter<T> getSorter(){

           String implClassName=IMPLS.getProperty("sorter");

           try{

                 Class implClass =Class.forName(implClassName);

                 return (Sorter<T>)implClass.newInstance();

           }catch(Exception e){

              throw new IllegalArgumentException("Illegal class name:"+implClassName,e);}

      }

}

创建 sort.properties 文件: sorter=demo.sort.impl.BubbleSorter

改进评估:不再通过传递参数的方式,而是通过外部配置,加载 Sorter 的具体算法类完全限定名。

                 如果文件中没有配置,则使用默认配置。

优劣评估:1.如果使用新的排序算法,只需要再文件中配置完全限定名,getSorter()代码不需要再

                   修改,保持了代码的稳定性。符合 OCP 原则。

                 2.Client 类不需要再关注算法细节,不需要传递算法的完全限定名。

                    使用新的算法的时候,Client 不需要修改代码。保持了代码的稳定性。符合 OCP。

                 3.缺少编译期类型安全。

引申: spring.handler=...........配置?思考?


用户头像

张荣召

关注

还未添加个人签名 2018.05.02 加入

还未添加个人简介

评论

发布
暂无评论
设计模式--正确学习姿势