设计模式之策略模式

释放双眼,带上耳机,听听看~!

今天和大家分享一下设计模式中的策略模式,这里只是分享楼主自己的见解,如有考虑不恰当的地方,还请理解,那么我们言归正传。由于楼主自己工作的原因,常常需要将数据库中资源数据生成相应的静态化文件(json文件),也就是俗称的打包。资源数据可能有很多种类型。例如:新闻、电影、小说等。不同的类型,在打包时,有不一样的流程,例如新闻和电影就有很大的不同,新闻在打包后还有要自动上传功能,这是因为对新闻的实效性要求很高,自动上传成功后,会自动调用下发服务器的下发指令,来自动更新APP中的新闻数据。而电影就不需要有此功能,一是因为电影的打包文件相比新闻太大,所以没必要调用自动上传接口,因为这样上传会比较慢,还不一定能保证电影包的完整性。二是因为电影会因一些版权等原因,需要人工审批。所以,电影和新闻相比就少了一个自动上传的功能。

下面我们按照上面的需求来设计我们相关的类,虽然新闻和电影有不同的打包流程,但我们分析后知道,除了生成json文件(数据不同)和自动上传功能不同外,其他的流程是可以公用的,那么按照面向对象的思想,我们应该设计出一个超类,将新闻和电影两个模块中相同的打包流程,在超类中实现,将两个模块不同的打包流程设计成抽象方法让它们的子类去实现,这样就可以将相同的打包流程复用了。具体的代码如下:

public abstract class AppPack {

  /**
   * 初始化 如:创建相应文件夹、定义一些打包参数等
   */
  public void doInit() {
    System.out.println("初始化");
  }

  /**
   * 生成json文件
   */
  public abstract void createJson();

  /**
   * 将生成的资源包打包ZIP文件
   */
  public void doZip() {
    System.out.println("打包ZIP文件");
  }

  /**
   * 将ZIP文件自动上传 (只有新闻有此流程)
   */
  public abstract void doUpload();
}
public class NewsAppPack extends AppPack {

  public void createJson() {
    System.out.println("生成新闻json文件");
  }

  public void doUpload() {
    System.out.println("自动上传ZIP包");
  }
}
public class VideoAppPack extends AppPack {

  public void createJson() {
    System.out.println("生成电影json文件");
  }

  public void doUpload() {
    // 因为电影没有此功能所以什么都不需要写
  }
}
public class Test {

  public static void pack(AppPack appPack) {
    appPack.doInit();
    appPack.createJson();
    appPack.doZip();
    appPack.doUpload();
  }

  public static void main(String[] args) {
    AppPack appPack = new NewsAppPack();
    pack(appPack);
    System.out.println("---------------");
    appPack = new VideoAppPack()
    pack(appPack);
  }

}
初始化
生成新闻json文件
打包ZIP文件
自动上传ZIP包
---------------
初始化
生成电影json文件
打包ZIP文件

现在看似乎没有什么问题,但是如果,我要把小说,游戏等模块都添加进来呢?上面的设计似乎就不太合理了,因为按照上面的设计,每一个子类都会默认继承doUpload()方法,按照我们之前的分析,暂时只有新闻模块是需要这个功能,其他的模块都不需要,那么这时我们子类就会包括大量的空实现。又如果我们的需求变了,其他的模块也需要有上传功能,但是是不同于新闻模块的上传逻辑的,那么上面的设计的代码就不用复用了,这就违背了面向对象的思想了。

现在我们知道使用继承并不能很好的解决我们遇到的问题,现在我们只能借助于设计模式了。我们首先看设计模式中的第一个原则:

  • 找出程序中可能变化的,把它们提取出来,不要和那些不需要变化的代码放在一起。

在说的简单点就是,如果每次我们有新的需求开发时,如果要修改曾经已经编码好的代码时,那么我们基本可以确定,要把这一部分提取出来,和其他已经编写好的稳定的代码分开。

按照我们之前的分析,我们知道打包类中只有两部分是变化的,也就是生成json文件和自动上传这两个方法,所以我们把这两个方法提取出来,这样我们就可以把这两个打包流程和真正的打包类分离了。

既然我们已经知道了要把生成json文件和自动上传功能要分离,那我们到底要怎么分离呢,也就是我们到底创建相关的类分离还是接口分离呢?这里还有一个可以遵循的设计模式原则,也就是本篇中的第二个设计模式原则:

  • 针对接口编程,而不是针对实现编程。

针对接口编程的意思是说针对超类型编程,针对接口编程的好处是,可以利用多态,这样程序执行的时候,会根据真正执行的子类类型来执行。

在说的简单点就是我们知道一个接口可以有很多个实现类,至于一共有哪些实现类,接口是不需要知道的,调用时只要实例化这个实现类并指向该接口就可执行调用,如果有新的实现类,只要新实例化这个新类即可,对接口方法的调用没有改变,这样就很方便扩展。

既然我们知道应该针对接口编程,那么我们需要把生成json文件和自动上传这两个打包流程设计成两个接口,然后设计不同的子类实现它们,让子类去实现它们原有的逻辑。下面是具体的代码。

public interface CreateJson {

  /**
   * 生成json文件
   */
  public void createJson();
}
public interface Upload {
  /**
   * 将ZIP文件自动上传
   */
  public void doUpload();

}
public class NewsCreateJson implements CreateJson {

  public void createJson() {
    System.out.println("生成新闻json文件");
  }
}
public class VidwoCreateJson implements CreateJson {

  public void createJson() {
    System.out.println("生成电影json文件");
  }
}
public class NeedUpload implements Upload {

  public void doUpload() {
    System.out.println("ZIP文件自动上传");
  }
}
public class NoNeedUpload implements Upload {

  public void doUpload() {
    System.out.println("ZIP文件不自动上传");
  }
}

这样我们已经把生成json文件和自动上传两个流程的接口设计完了,那我们怎么改原先的打包类呢?按照我们上面了解的那样,我们需要针对接口编程,所以,我们需要把我们新设计的json文件和自动上传这两个流程的接口放到原先的打包类中,而原先的打包类中已经不需要自己处理这两部分流程了,具体的流程而是我们已经设计好的相关的子类去实现。这样我们就可以用多态的特性,动态改变它们的执行流程了。具体代码如下:

public abstract class AppPack {

  public CreateJson createJson; // 生成json文件接口
  public Upload upload; // 上传文件接口

  /**
   * 初始化 如:创建相应文件夹、定义一些打包参数等
   */
  public void doInit() {
    System.out.println("初始化");
  }

  /**
   * 生成json文件
   */
  public void createJson() {
    createJson.createJson(); // 相关的子类去实现
  }

  /**
   * 将生成的资源包打包ZIP文件
   */
  public void doZip() {
    System.out.println("打包ZIP文件");
  }

  /**
   * 将ZIP文件自动上传
   */
  public void doUpload() {
    upload.doUpload(); // 相关的子类去实现
  }
}
public class NewsAppPack extends AppPack {

  public NewsAppPack() {
    createJson = new NewsCreateJson(); // 调用生成新闻json的子类
    upload = new NeedUpload(); // 调用自动上传的子类
  }

}
public class VideoAppPack extends AppPack {

  public VideoAppPack() {
    createJson = new VidwoCreateJson(); // 调用生成电影的json子类
    upload = new NoNeedUpload(); // 调用不自动上传的子类
  }
}
public class Test {

  public static void pack(AppPack appPack) {
    appPack.doInit();
    appPack.createJson();
    appPack.doZip();
    appPack.doUpload();
  }

  public static void main(String[] args) {
    AppPack appPack = new NewsAppPack();
    pack(appPack);    
    System.out.println("---------------");
    appPack = new VideoAppPack()    
    pack(appPack);
  }

}
初始化
生成新闻json文件
打包ZIP文件
ZIP文件自动上传
---------------
初始化
生成电影json文件
打包ZIP文件
ZIP文件不自动上传

这样我们已经把生成json文件和自动上传相关的流程已经和打包类分离了。这样设计不但方便了我们日后扩展,我们还可以直接动态的改变原有的流程。具体代码如下:

public abstract class AppPack {

  public CreateJson createJson; // 生成json文件接口
  public Upload upload; // 上传文件接口

  /**
   * 初始化 如:创建相应文件夹、定义一些打包参数等
   */
  public void doInit() {
    System.out.println("初始化");
  }

  /**
   * 生成json文件
   */
  public void createJson() {
    createJson.createJson(); // 相关的子类去实现
  }

  /**
   * 将生成的资源包打包ZIP文件
   */
  public void doZip() {
    System.out.println("打包ZIP文件");
  }

  /**
   * 将ZIP文件自动上传
   */
  public void doUpload() {
    upload.doUpload(); // 相关的子类去实现
  }

  /**
   * 设置生成json文件策略
   * @param createJson
   */
  public void setCreateJson(CreateJson createJson) {
    this.createJson = createJson;
  }

  /**
   * 设置自动上传策略
   * 
   * @param upload
   */
  public void setUpload(Upload upload) {
    this.upload = upload;
  }
}
public class Test {

  public static void pack(AppPack appPack) {
    appPack.doInit();
    appPack.createJson();
    appPack.doZip();
    appPack.doUpload();
  }

  public static void main(String[] args) {
    AppPack appPack = new NewsAppPack();
    pack(appPack);
    appPack.setUpload(new NoNeedUpload());
    System.out.println("---------------");
    pack(appPack);
  }

}

这样我们就可以动态的改变原有打包类中的打包逻辑了。

这就是策略模式的具体应用。下面我们看策略模式的具体定义。

策略模式的定义:定义了算法组,分别封装起来,让它们之间可以互相替换,此模式让算法的变化独立于使用算法的客户。

这就是我对设计模式中策略模式的理解 ,如本文有不正确之处,欢迎指出。谢谢。

0 条回复 A文章作者 M管理员
    暂无讨论,说说你的看法吧