设计模式实战:原型模式实现场景对象的复制

2021-09-23 15:49:56 浏览数 (2)

传送门:【设计模式系列(三)】彻底搞懂原型模式

## 需求

1、 有一个程序,会有多个不同的用户并发访问

2、程序中包含多个场景,根据用户首次访问的输入内容匹配得到符合条件的场景

3、不同的场景需要对外提供统一的匹配和处理输入的接口,但处理逻辑和方法又各不相同

4、同一个用户存在多轮次访问的情况,并且场景会根据多轮访问的情况决定当前轮次的处理方法,要求每个用户要有一个独立的场景对象处理用户的输入内容

5、每个用户有一个独立的id标识

## 类图

1、定义一个场景抽象类,具体场景类继承抽象类,并实现初始化方法和处理输入方法

2、抽象类实现Cloneabel接口以实现原型模式,实现Serializable接口以实现对象的深度克隆

3、定义SceneMatchWord类,实现场景的匹配功能

4、定义SceneContext类用来存储场景实例对象,并提供匹配和获取场景的唯一接口方法

5、定义Main类,作为模拟程序的入口接口,通过控制台输入模拟用户输入

## 主要代码

### 场景抽象类

代码语言:javascript复制
/**
 * 场景超类
 * @author daijiyong
 */
abstract public class AbstractScene implements Cloneable, Serializable {
    /**
     * 场景名字
     */
    public SceneNameCode sceneNameCode;
    /**
     * 当前场景的匹配词
     */
    protected LinkedList<SceneMatchWord> matchWords;
    public AbstractScene() {
    }
    public AbstractScene(SceneNameCode sceneNameCode) {
        this.sceneNameCode = sceneNameCode;
    }
    /**
     * 对外统一处理操作,子类进行重写
     */
    public abstract String deal(String userInput);
    /**
     * 初始化操作,子类进行重写
     */
    protected abstract void init();
    /**
     * 根据用户输入与当前场景进行匹配
     *
     * @param userInput 用户输入内容
     * @return 匹配结果
     */
    public Boolean match(String userInput) {
        // TODO
        //  根据用户的输入进行匹配
        //  匹配成功则返回true,失败则返回false
        for (SceneMatchWord smw : matchWords) {
            if (smw.match(userInput)) {
                return true;
            }
        }
        return false;
    }
    /**
     * 深克隆
     *
     * @return 克隆结果
     */
    @Override
    public AbstractScene clone() {
        AbstractScene clone = null;
        try {
            clone = (AbstractScene) super.clone();
            ByteArrayOutputStream bo = new ByteArrayOutputStream();
            ObjectOutputStream oos = new ObjectOutputStream(bo);
            oos.writeObject(this);
            ByteArrayInputStream bi = new ByteArrayInputStream(bo.toByteArray());
            ObjectInputStream oi = new ObjectInputStream(bi);
            clone = (AbstractScene) oi.readObject();
        } catch (IOException | ClassNotFoundException | CloneNotSupportedException e) {
            e.printStackTrace();
        }
        return clone;
    }
}

### 场景子类

代码语言:javascript复制
public class NumberReverseQueryScene extends AbstractScene {
    public NumberReverseQueryScene(SceneNameCode sceneNameCode) {
        super(sceneNameCode);
        init();
    }
    @Override
    public String deal(String userInput) {
        // TODO
        //  当前场景对用户输入的具体实现
        //  并返回结果
        return String.format("%s处理用户的输入内容%sn", sceneNameCode.getName(), userInput);
    }
    /**
     * 初始化当前场景数据
     */
    @Override
    public void init() {
        // 初始化匹配内容
        matchWords = new LinkedList<>();
        //5个或5个以上数字,不含字母,非1非0开头号码
        matchWords.add(new SceneMatchWord(Pattern.compile("[2-9]\d{4,}")));
        //5个或5个以上数字,不含字母,1开头号码
        matchWords.add(new SceneMatchWord(Pattern.compile("1\d{4,}")));
    }
}

### 场景匹配规则类

代码语言:javascript复制
/**
 * 场景匹配词
 *
 * @author daijiyong
 */
public class SceneMatchWord implements Serializable {
    // 匹配规则
    private Pattern rule;
    /**
     * 根据用户输入内容进行匹配
     * 匹配成功返回true,失败返回false
     *
     * @param userInput 用户输入
     * @return 匹配成功或失败
     */
    public Boolean match(String userInput) {
        return matchRule(userInput);
    }
    private boolean matchRule(String str) {
        if (rule == null) {
            return false;
        }
        return rule.matcher(str).find();
    }
}

### 场景上下文类

初始化场景对象

调用场景的匹配方法,根据用户的输入为每一个用户创建一个特有的场景对象 并使用ConcurrentHashMap来存储不同用户的场景对象

代码语言:javascript复制
public class SceneContext {
    private final static Map<String, AbstractScene> CONTEXT = new ConcurrentHashMap<>();
    private final static ArrayList<AbstractScene> SCENES = new ArrayList<>();
    static {
        // 初始化场景集合
        SCENES.add(SceneFactory.createNumberReverseQueryScene());
        SCENES.add(SceneFactory.createMoveCarScene());
        SCENES.add(SceneFactory.createAreaCodeReverseQueryScene());
    }
    public static AbstractScene currentScene(String queryId, String userInput) {
        if (getContext().get(queryId) == null && SCENES.size() > 0) {
            for (AbstractScene as : SCENES) {
                if (as.match(userInput)) {
                    CONTEXT.put(queryId, as.clone());
                    System.out.printf("用户%s匹配到场景:%sn", queryId, as.sceneNameCode.getName());
                    return getContext().get(queryId);
                }
            }
        }
        return getContext().get(queryId);
    }
    public static Map<String, AbstractScene> getContext() {
        return CONTEXT;
    }
}

### 模拟程序入口类

代码语言:javascript复制
/*
   模拟入口程序
 */
public class Main {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        while (scanner.hasNext()) {
            // 输入两个内容,用户id和用户请求内容,中间用空格隔开
            String input = scanner.nextLine();
            String[] inputArr = input.split(" ");
            AbstractScene scene = SceneContext.currentScene(inputArr[0], inputArr[1]);
            System.out.println(scene.deal(inputArr[1]));
        }
    }
}

运行程序,可实现为每个用户创建独立的场景对象

点击阅读原文访问完整代码地址

包路径:com/dai/designpattern/prototype/practice

文/戴先生@2021年9月13日

---end---

0 人点赞