前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >设计模式实战:原型模式实现场景对象的复制

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

作者头像
你好戴先生
发布2021-09-23 15:49:56
3890
发布2021-09-23 15:49:56
举报
文章被收录于专栏:戴言泛滥

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

## 需求

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处理用户的输入内容%s\n", 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匹配到场景:%s\n", 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---

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2021-09-14,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 你好戴先生 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档