设计模式(五)原型模式

1.前言

  1. 使用场景:
  • 当创建一个对象的前置操作会耗费非常多的资源时。比如初始化一个实例需要查询多个数据库的时候,这个时候我们只需要考虑输入输出时候存在唯一对应关系,如果是的话就可以将结果缓存起来,当下次需要再次生产该类型的对象时clone一份就可以,节省了巨大的系统资源。
  • 当类的实例种类有限时。因为原型模式实际上就是一种缓存模式,当类的实例类型很多的时候比如:animals类,根据场景不同产生的实例有接近无限多个,这个时候使用原型模式(缓存)肯定是得不偿失的。
  1. 优点:
  • 节省资源。
  • 逃避构造函数的约束。
  1. 缺点
  • 由于是clone方式,所以引用类型引起的隐患使我们必须考虑的,根据不同场景使用不同的方式实现原型模式。
  • 系统复杂度必然有所提高。对于复杂场景的适配可能会造成复杂度的成倍提升(和new一个对象相比,判断是浅拷贝还是深拷贝,什么类型用什么设计,显然复杂多了,建议对简单对象和必须优化对象使用该模式)。

2. 例子

在这里插入图片描述

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>原型模式</title>
</head>

<body>
    <script>
        class Utils {
            constructor() {
                this.map = new WeakMap();
                this.deepCopy = this.deepCopy.bind(this);
            }

            deepCopy(obj){
                let { map } = this;
                let deepCopy = this.deepCopy;
                //如果是基本类型则直接返回
                if (typeof obj !== "object") {
                    return obj;
                }

                //如果是引用类型,则判断是否是循环引用的对象
                if (map.get(obj)) {
                    return {};
                }

                //如果是null
                if (!obj) {
                    return null;
                }

                //此时细分类型
                const obj_type = Object.prototype.toString.call(obj);

                let temp_obj = null;
                //如果是数组则迭代deepcopy
                if (obj_type.includes("Array")) {
                    //缓存obj,留待下次判断是否循环引用
                    map.set(obj, obj_type);
                    temp_obj = [];
                    obj.forEach((item) => {
                        temp_obj.push(deepCopy(item));
                    });
                }

                //如果是对象的话,迭代deepcopy直到基本类型
                if (obj_type.includes("Object")) {
                    map.set(obj, obj_type);
                    temp_obj = {};
                    Reflect.ownKeys(obj).forEach((key) => {
                        temp_obj[key] = deepCopy(obj[key]);
                    });
                }

                return temp_obj;
            }
        }
        let u = new Utils();

        class DbItem {
            constructor(name, createTime) {
                this.dbName = name;
                this.createTime = createTime;
            }
        }

        class GetDbItem{
            constructor(){
                this.dbItemMap = new Map();
            }

            getDbItem(name){
                let {dbItemMap} = this;

                if(!name){
                    throw new Error("no name!")
                    return ;
                }

                //clone原型
                if(dbItemMap && dbItemMap.get(name)){
                    console.log("cloned");
                    return u.deepCopy(dbItemMap.get(name));
                }

                //生成原型
                let newDb = new DbItem(name,Date.now());
                dbItemMap.set(name,newDb);
                return newDb;
            }
        }

        let getDBItemInstance = new GetDbItem();
        let d1 = getDBItemInstance.getDbItem("db1");
        let d2 = getDBItemInstance.getDbItem("db1");
        console.log(d1);
        console.log(d2);
    </script>
</body>

</html>

3. 后记

原型其实就是缓存功能+clone功能,使用时记得关注内存占用和使用场景,否则可能会造成不必要的浪费。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值