根据实际开发需求如何采用设计模式-抽象工厂模式(半年经验的菜鸡)

现在是11月12号 我是5月份中旬步入这家公司的,差不多有半年之久了,中间花几个月看了设计模式,所以在实际业务中套用了一些设计模式来写代码,在此记录一下,所以写的不好 切勿喷/(ㄒoㄒ)/~~

1.什么是抽象工厂模式?

概念:提供一个接口以创建一系列相关或 互相依赖的对象,而无需指定他们的类。

换言之,使用者仅与抽象类定义的接口交互,而不适用特定的具体类接口

瞧瞧 瞧瞧这句话 有一说一 我在刚开始学的时候真的读不懂这句话。我来以菜鸡的角度理解一下这句话。

"仅调取 一个方法 他将返回 一系列(或更多) 的方法来产生对象"

重点在 "一系列" 可能还是有些不明不白 别着急 下面用具体业务实例 来引用抽象工厂来解决方法

抽象工厂优缺点

优点:可以创建多个产品进行多次组合,下面的实例会讲到,如果创建2个echarts 和 2个控制器那么他们组合的方方法有 2的立方,那么如果创建更多的产品,那么他们的组合那就太多了

缺点:一旦创建过的产品,他们之间进行了组合为了工厂,会使其耦合度变高,不能随随便便的修改其中任何的一个产品

前提:本人公司是在做toB项目,面向做大屏的业务及其的多,也是经验积累发现他们的共同之处,用该模式来重构我的 echarts 图表的业务

业务需求

用一个图表并且需要一个 条件或多个条件来与图表(echarts)的数据做关联 类似的原型图大概这样 ↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓

如果说按平常的方式是如何调取echarts 图表 放在页面 ,并且还需要一个search或者select来控制echarts呢

xml 复制代码
<body>
    <!-- 为ECharts准备一个具备大小(宽高)的Dom -->
    <select name="" id="controller">
        <option value="">数据1</option>
        <option value="">数据2</option>
        <option value="">数据3</option>
    </select>
    <div id="main" style="width: 300px;height:200px;"></div>

    <script type="text/javascript">
        document.querySelector('#controller').addEventListener('click', (event) => {
            (省略代码)。。。。
            test('#main', data)
        })
        // 基于准备好的dom,初始化echarts实例
        function test(dom, data) {
            var myChart = echarts.init(document.querySelector(dom));
            // 指定图表的配置项和数据
            var option = data;
            myChart.setOption(option);
        }
    </script>
</body>

以上代码甚至还是只是创建一个echarts图表部分,

那么如果一个页面创建6个 12个呢,甚至更多呢 一旦突然一天后端告知,可能调取数据接口,加个字段,少个字段,好了,这一下全都得改了,这不得疯掉了

那为何使用抽象工厂模式呢

我们可以把 创建代码中的 controller 控制器部分(例如select,search)部分,抽象抽离出来

不需要每次都写代码,调用一个方法动态生成出来,并且与echarts 所关联起来,说到动态生成了,那当然我们的echarts 部分也需要如此

当然图表不只有echarts 还有其他大厂图表库,BizCharts,g2 等等 我们把select 和search 抽离出来 他们统称为什么?可以说是"控制组件" 把echarts g2 等等图表抽离出来统称为"图表组件"

创建 工厂类 和 产品类

javascript 复制代码
// 抽象工厂 用来表明 该类 只是为了继承创建一个拥有 图表 和 控制器的 组件,它不能被用于生成具体实例
class createComponet {
  creatcharts() {
    throw new Error('抽象方法,用于实现创建 图表')
  }
  createCondition() {
    throw new Error('抽象方法,用于实现创建 控制器')
  }
}
// 抽象产品 该来 只是为了继承创建图表
class chart{
  createChart(){
    throw new Error('抽象方法 用于创建不用类型的图表')
  }
}
// 抽象产品 该来 只是为了继承创建图表
class condition{
  createCondition(){
    throw new Error('抽象方法 用于创建不用类型的控制器')
  }
}

创建 具体产品和 具体工厂 为什么 先创建产品,再创建工厂呢,那肯定 产品的组合 即 就是 工厂嘛

scala 复制代码
// 创建 echarts 图表产品
class Echarts extends chart{
  createChart(dom){
      var myChart = echarts.init(document.querySelector(dom));
    // 指定图表的配置项和数据
    var option = {
        tooltip: {},
        legend: {
            data:['销量']
        },
        xAxis: {
            data: ["衬衫","羊毛衫","雪纺衫","裤子","高跟鞋","袜子"]
        },
        yAxis: {},
        series: [{
            name: '销量',
            type: 'bar',
            data: [5, 20, 36, 10, 10, 20]
        }]
    };
    myChart.setOption(option);
  }
}
// 创建 G2  图表产品
class G21 extends chart{
  createChart(dom){
      const data = [
      { year: '1991', value: 15468 },
      { year: '1992', value: 16100 },
      { year: '1993', value: 15900 },
      { year: '1994', value: 17409 },
      { year: '1995', value: 17000 },
      { year: '1996', value: 31056 },
      { year: '1997', value: 31982 },
      { year: '1998', value: 32040 },
      { year: '1999', value: 33233 },
    ];
    const chart = new G2.Chart({
      container: `${dom}`,
      autoFit: true,
    });
    chart.data(data);
    chart.scale({
      value: {
        min: 10000,
        nice: true,
      },
      year: {
        range: [0, 1],
      },
    });
    chart.tooltip({
      showCrosshairs: true,
      shared: true,
    });
    chart.axis('value', {
      label: {
        formatter: (val) => {
          return (+val / 10000).toFixed(1) + 'k';
        },
      },
    });
    chart.area().position('year*value');
    chart.line().position('year*value');
    chart.render();
  }
}
// 创建 搜索 产品
class Search extends condition{
  createCondition(dom){
    let condition = `<input type="text"><button>搜索</button>`
    document.querySelector(dom).innerHTML = condition
  }
}
// 创建 下拉框 产品
class select extends condition{
  createCondition(dom){
    let condition = `<select>
    <option>数据1</option>
    <option>数据2</option>
    <option>数据3</option>
    </select>`
    document.querySelector(dom).innerHTML = condition
  }
}

组合产品 产生 工厂

scala 复制代码
// 创建一个由echarts 和search的 工厂
class createEcharts extends createComponet{
  echarts(dom){
    return new Echarts(dom)
  }
  search(dom){
    return new Search(dom)
  }
}
// 组合一个由g2 和select的 工厂
class createG2 extends createComponet {
  G2(dom){
    return new G21(dom)
  }
  select(dom){
    return new select(dom)
  }
}

那么 如何使用呢?

xml 复制代码
<body>
  <script src="https://gw.alipayobjects.com/os/lib/antv/g2/4.2.7/dist/g2.min.js"></script>
  <script src="https://gw.alipayobjects.com/os/antv/pkg/_antv.data-set-0.11.1/dist/data-set.js"></script>
  <script src="https://cdn.staticfile.org/echarts/4.3.0/echarts.min.js"></script>
  <script src="./test.js"></script>
  <div class="box">
    <div id="condition1">条件</div>
    <div id="chart1" class="chart"></div>
  </div>
  <div class="box">
    <div id="condition2">条件</div>
    <div id="chart2" class="chart"></div>
  </div>

  <style>
    .box {
      width: 300px;
      height: 300px;
      border: 1px solid black;
    }

    .chart {
      width: 100%;
      height: 260px;
      margin-top: 10px;
    }
  </style>
  <script>
    function setEcharts() {
      let ctEcharts = new createEcharts()
      let ECharts = ctEcharts.echarts()
      ECharts.createChart('#chart1')
      let search = ctEcharts.search()
      search.createCondition('#condition1')
    }
    function setG2(){
      let ctG2= new createG2()
      let select = ctG2.select()
      select.createCondition('#condition2')
      let G2 = ctG2.G2()
      G2.createChart('chart2')
    }
    setEcharts()
    setG2()
  </script>
</body>

当然 实际开发中的代码不止这些

其中的echarts 和 g2 中的option配置部分也是需要抽离出来,来保证单一原则

这么做也是为了 在每次触发search 或者 select 改变时 创建option 来导入 图表当中,来达到控制 图表 以上代码中 创建的 echarts 控制器为search

如果一天需求变了,需要的是一个下拉框select呢

这时候抽象工厂的好处就来了

csharp 复制代码
// 重新组合 产品 创建具体工厂
class createEchartsAndSelect extends createComponet {
  echarts(dom){
    return new Echarts(dom)
  }
  select(dom){
    return new select(dom)
  }
}
function setEchartsAndSelect() {
      let ctEcharts = new createEcharts()
      let ECharts = ctEcharts.echarts()
      ECharts.createChart('#chart1')
      let select = ctEcharts.select()
      select.createCondition('#condition1')
    }

反之g2 图表也可以与其他控制器组合 或许说有一天select和search 都不满足业务中的需求了,又来一个 日期选择器的 控制器

scala 复制代码
// 创建 搜索 产品
class date extends condition{
  createCondition(dom){
    具体业务代码.....
  }
}

然后又可以重新组合多个工厂

这也就是抽象创建工厂的强大的地方

总结

其实在实际开发中业务逻辑也是特别复杂的,设计模式只是把一种复杂转换成了另一种复杂形式用于管理,在实际开发中我也会使用其他的设计模式,如果有时间我仍会总结出来,发帖记录一下

ps:但最近一直在学习计算机网络知识,看b站看书,发博客的日子也不定什么时候会发,群友也总说我怎么一直怎么卷

我的想法就是既然大佬对这种东西手拿把捏,我想我这种工作不久的菜鸡也得摸着大佬走过的路慢慢走过来,其实最近在工作中倒是有了新的开源想法,不知道在后面的日子会不会去实现,就这吧

相关推荐
滚雪球~17 分钟前
npm error code ETIMEDOUT
前端·npm·node.js
沙漏无语19 分钟前
npm : 无法加载文件 D:\Nodejs\node_global\npm.ps1,因为在此系统上禁止运行脚本
前端·npm·node.js
supermapsupport20 分钟前
iClient3D for Cesium在Vue中快速实现场景卷帘
前端·vue.js·3d·cesium·supermap
brrdg_sefg22 分钟前
WEB 漏洞 - 文件包含漏洞深度解析
前端·网络·安全
胡西风_foxww28 分钟前
【es6复习笔记】rest参数(7)
前端·笔记·es6·参数·rest
m0_7482548829 分钟前
vue+elementui实现下拉表格多选+搜索+分页+回显+全选2.0
前端·vue.js·elementui
星就前端叭1 小时前
【开源】一款基于Vue3 + WebRTC + Node + SRS + FFmpeg搭建的直播间项目
前端·后端·开源·webrtc
m0_748234521 小时前
前端Vue3字体优化三部曲(webFont、font-spider、spa-font-spider-webpack-plugin)
前端·webpack·node.js
Web阿成1 小时前
3.学习webpack配置 尝试打包ts文件
前端·学习·webpack·typescript
jwensh2 小时前
【Jenkins】Declarative和Scripted两种脚本模式有什么具体的区别
运维·前端·jenkins