设计模式之 ==> 策略设计模式

一、什么是策略设计模式

  策略设计模式(Strategy Pattern)定义了一系列的算法,并将每一个算法封装起来,而且使它们之间可以互相替换。策略模式让算法的变化不会影响到使用算法的客户。

  分析下定义,策略模式定义和封装了一系列的算法,它们是可以相互替换的,也就是说它们具有共性,而它们的共性就体现在策略接口的行为上,另外为了达到最后一句话的目的,也就是说让算法独立于使用它的客户而独立变化,我们需要让客户端依赖于策略接口。

二、策略设计模式结构图

这个类图并不复杂,右边是策略接口以及它的实现类,左边会有一个上下文,这个上下文会拥有一个策略,而具体这个策略是哪一种,我们是可以随意替换的

三、策略模式写法举例

我们需要实现这样一个功能:

  • 我们需要对一批不同格式的文件进行处理
  • 文件类型有 mp4,avi,rmvb,不同格式的文件使用不同的文件解析器来解析文件
  • 文件类型可不一定只有这几种,随着业务的扩展会不断增加, 比如 : txt, jpg,png等等

下面,我们使用策略设计模式来实现这个功能:

首先,先来定义一个文件类型的枚举和自定义的一个文件类,用于描述我们处理的文件类型

public class MyFile {
    private FileType fileType;
    private String fileName;
    private String filePath;

    public MyFile(Builder builder) {
        this.fileType = builder.fileType;
        this.fileName = builder.fileName;
        this.filePath = builder.filePath;
    }

    public static Builder builder() {
        return new Builder();
    }

    public static class Builder {
        private FileType fileType;
        private String fileName;
        private String filePath;

        public Builder fileType(FileType fileType) {
            this.fileType = fileType;
            return this;
        }

        public Builder fileName(String fileName) {
            this.fileName = fileName;
            return this;
        }

        public Builder filePath(String filePath) {
            this.filePath = filePath;
            return this;
        }

        public MyFile build() {
            return new MyFile(this);
        }
    }

    public FileType getFileType() {
        return fileType;
    }

    public String getFileName() {
        return fileName;
    }

    public String getFilePath() {
        return filePath;
    }

    @Override
    public String toString() {
        return "MyFile{" +
                "fileType=" + fileType +
                ", fileName='" + fileName + '\'' +
                ", filePath='" + filePath + '\'' +
                '}';
    }
}
MyFile
public enum FileType {
    MP4,
    AVI,
    RMVB,
    PNG
}
FileType

再来,定义策略接口,相当于结构图中的 Strategy 接口

public interface IStrategy<T> {

  void parse(T t);
}

这里也可以不使用泛型,因为我们在前面定义了文件描述的类 MyFile

然后,是三个具体的策略类,分别是 mp4,avi,rmvb 三种格式文件的解析器,相当于结构图中的 ConcreteStrategy

public class Mp4ParserStrategy implements IStrategy<MyFile> {

  @Override
  public void parse(MyFile file) {
    System.out.println("Mp4ParserStrategy.parse file=" + file);
  }
}
Mp4ParserStrategy
public class AviParserStrategy implements IStrategy<MyFile> {

  @Override
  public void parse(MyFile file) {
    System.out.println("AviParserStrategy.parse file=" + file);
  }
}
AviParserStrategy
public class RmvbParserStrategy implements IStrategy<MyFile> {

  @Override
  public void parse(MyFile file) {
    System.out.println("RmvbParserStrategy.parse file=" + file);
  }
}
RmvbParserStrategy

这里没有实现解析器的功能,只是进行了简单的描述

再下来是上下文,又或者叫策略管理的类,相对于结构图中的 Context

public final class ParserStrategyManager {

  private final Map<FileType, IStrategy<MyFile>> strategyMap;

  private ParserStrategyManager() {
    this.strategyMap = Maps.newConcurrentMap();
    this.strategyMap.put(FileType.AVI, new AviParserStrategy());
    this.strategyMap.put(FileType.MP4, new Mp4ParserStrategy());
    this.strategyMap.put(FileType.RMVB, new RmvbParserStrategy());
  }

  public void doParser(MyFile file) {
    if (!strategyMap.containsKey(file.getFileType())) {
      throw new IllegalStateException("无法处理这种格式的文件");
    }
    this.strategyMap.get(file.getFileType()).parse(file);
  }

  private static class ClassHolder {
    private static final ParserStrategyManager INSTANCE = new ParserStrategyManager();
  }

  public static ParserStrategyManager getInstance() {
    return ClassHolder.INSTANCE;
  }
}
ParserStrategyManager

在这个类中,我们将文件类型和策略解析器以 Key,Value的形式存入一个Map当中,这样客户端在调用时只需传入文件的相关属性(包括文件类型),我们就根据文件类型找到文件对应的解析器进行解析,后续如果增加了其他的文件类型,只需要在 FileType 中增加类型并且增加具体的解析策略类,最后在 ParserStrategyManager 类中将文件类型和对应的解析策略类维护进 Map当中就可以了。

最后,来看一下客户端调用和结果

public class App {

  public static void main(String[] args) {

    MyFile file = MyFile.builder()
            .filePath("/home")
            .fileName("movie.avi")
            .fileType(FileType.AVI)
            .build();
    ParserStrategyManager.getInstance().doParser(file);
  }
}

运行结果:

根据运行结果可以看出,根据客户端传入的文件类型(AVI类型),找到了具体的解析策略 AviParserStrategy.parse 进行解析。

posted on 2020-09-25 19:02  破解孤独  阅读(307)  评论(0编辑  收藏  举报

导航