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

现在是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站看书,发博客的日子也不定什么时候会发,群友也总说我怎么一直怎么卷

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

相关推荐
天下无贼!1 小时前
2024年最新版Vue3学习笔记
前端·vue.js·笔记·学习·vue
Jiaberrr1 小时前
JS实现树形结构数据中特定节点及其子节点显示属性设置的技巧(可用于树形节点过滤筛选)
前端·javascript·tree·树形·过滤筛选
赵啸林1 小时前
npm发布插件超级简单版
前端·npm·node.js
罔闻_spider2 小时前
爬虫----webpack
前端·爬虫·webpack
吱吱鼠叔2 小时前
MATLAB数据文件读写:1.格式化读写文件
前端·数据库·matlab
爱喝水的小鼠2 小时前
Vue3(一) Vite创建Vue3工程,选项式API与组合式API;setup的使用;Vue中的响应式ref,reactive
前端·javascript·vue.js
盏灯2 小时前
前端开发,场景题:讲一下如何实现 ✍电子签名、🎨你画我猜?
前端
WeiShuai2 小时前
vue-cli3使用DllPlugin优化webpack打包性能
前端·javascript
Wandra2 小时前
很全但是超级易懂的border-radius讲解,让你快速回忆和上手
前端
ice___Cpu2 小时前
Linux 基本使用和 web 程序部署 ( 8000 字 Linux 入门 )
linux·运维·前端