【“别跟我不会”系列】Java设计模式之策略模式

  • 2019 年 10 月 8 日
  • 笔记

茶余饭后的IT小知识,不说了,都是干货。 —— 23号老板

0

1

引入

原创:爱吃回锅肉的瘦子

一直以来,笔主想写关于设计模式的系列文章与大家进行交流,但碍于自己经验上尚浅,无法将此讲解透彻,闹了笑话。但千里之行,始于足下,我决定将我自己的工作中我用到的设计模式与大家分享交流,有不妥还望大家指出。

设计模式一种设计开发上的经验总结,既然是经验上的总结,那么实践是必然的;但他又是一种设计,所以在我们对需求必须得非常了解,对他可能以后出现什么样的变化有个预测。此次我打算先从设计模式中的策略模式讲起。

0

2

概念

在策略模式中,一个类的行为或其算法可以在运行时更改。这种类型的设计模式属于行为型模式。

代码上的设计上大体架构:

1、抽象的行为:

  public interface Behavior {      public void toDo();  }

2、实现抽象行为的两个类

public class OneBehavior implements Behavior{ @Override public void toDo() { System.out.println("one"); } }

public class TwoBehavior implements Behavior {      @Override      public void toDo() {          System.out.println("two");      }  }

3、定义公有的行为类:

public class DataBase {      protected Behavior behavior;        public DataBase(Behavior behavior) {          this.behavior = behavior;      }
    public void query(){          behavior.toDo();      }
    public void delete(){          System.out.println("delete");      }    }

从上面代码架构上看,可以看到策略模式的方式本身就是将本身属于database中的某些方法抽离出来,用接口的方式来抽象方法。既然这样,那与我们常用的模板模式有什么区别呢?

为何不将database设计成抽象类,然后将此进行各个子类实现,我们也可以做到不同方法的实现。注意设计模式是结合具体场景而使用的一种经验模式。

0

3

深入

那么在什么样的场景下使用策略模式,有什么样的场景下使用模板模式呢?

我们知道,在对代码评价有个复用性比较,那么我们可以假设这样的一个场景

假设在query方法中 我们目前只有两种的查询逻辑方式,但是有9个查询需要使用,其中有6个是使用相同的query()。这样的话,在使用模板模式中我们对query()方法要写6个相同的代码。的确,我们还可以将这6个中再写一个父类继承,此父类再继承database,但是delete方法中在这6个有三个delete相同呢又或者其中三个delete方法又与前面3个子类相同呢?

这时候我们用模板模式来实现不同的方法是不可行的。必须将方法解耦化,如何解耦呢?将变化的方法抽象成接口,将database依赖于该接口,也就是说我们可以将接口作为属性给予database。综上,在笔主看来,策略模式就是将一些多变的方法抽象出来,来增加代码的复用。

注意点:

1、分析项目中的变化部分与不变部分;

2、多用组合少用继承;用行为类组合,而不是行为的继承,更有弹性;

0

4

实战部分

笔主是主要开发报表功能的,难免牵扯到生成excel。我这边生成excel有三种方式,poi,easyExcel,以及第三方软件。他们各个使用方式有不同的划分。如果想了解Excel是如何使用poi解析的可以看看前面的文章。(如果找不见,可加微信bboyHan索要)

那么我那时候为啥选择使用策略模式,是基于什么样的考量呢?这里就开始讨论方法论了。刚开始的时候 ,获取Excel不是那么复杂, 我只是单纯的使用POI方式生成excel,后面由于有性能上要求,就使用上了easyExcel,在后来excel表格复杂化了,为了便于维护就使用上了第三方软件功能,再后来运营还要求导出pdf。当然了,这些是需求在讨论时候就已经确认要分多次迭代了。如果是三张报表,分别用这三个获取excel方式,那简单使用mvc模型就差不多解决了。但是笔主面对的是几百张报表,必须得将此抽离出来所有的导出功能。也就是我设计一个接口 getFile(),三个行为类poi、easyExcel、第三方实现getFile();再写一个参数基本类,将选择什么样方式导出放在此处,然后在写一个获取数据获取类,并依赖getFile类。代码如下:

public interface GetFile {      public File toDo();  }
public class PoiFile implements GetFile {      @Override      public File toDo() {          System.out.println("poi");          return new File("poi");      }  }
public class EasyExcelFile implements GetFile {      @Override      public File toDo() {          System.out.println("EasyExcel");          return new File("EasyExcel");      }    }
public class DataBase {      protected GetFile getFile;        public DataBase(GetFile behavior) {          this.getFile = behavior;      }      public void query(){          getFile.toDo();      }      public void delete(){          System.out.println("delete");      }    }
public class TwoData extends DataBase {        public TwoData(GetFile file) {          super(file);      }        @Override      public void query() {          this.getFile.toDo();      }  }
public class OneData extends DataBase{        public OneData(GetFile getFile) {          super(getFile);      }      @Override      public void query() {          this.getFile.toDo();      }  }

参数类:

public class RequestModel implements Serializable {      private String type;        public GetFile getFile(){          if("POI".equalsIgnoreCase(getType()))return new PoiFile();          else return new EasyExcelFile();      }        public String getType() {          return type;      }
    public void setType(String type) {          this.type = type;      }
}

service层:

//交给sring管理DataBase dataBase;  public void query(RequestModel rq){       dataBase.query();  }

0

5

小结

以上就是策略模式实现方式,简单来说,可以理解为将多变的方法抽离出来,进行解耦合。