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

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

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

相关推荐
猫猫不是喵喵.26 分钟前
Vue3 Props 属性
前端·javascript·vue.js
醉城夜风~1 小时前
CSS元素显示模式(display)
前端·css
AI大模型-小华2 小时前
Codex 三方充值快速入门指南
java·前端·数据库·chatgpt·ai编程·codex·chatgpt pro
做前端的娜娜子4 小时前
同一链接实现 PC Web 与移动 H5 自适应
前端·掘金·金石计划
小帅不太帅5 小时前
架构没变、规模没变,DeepSeek V4 Flash 正式版凭什么暴涨 47 分?
前端·aigc·deepseek
jarvisuni5 小时前
DeepSeekFlash前端依旧拉垮,而且变慢了很多!
前端·javascript·算法
卷福同学6 小时前
AI编程出海第二步:验证关键词能否做站
前端·人工智能·后端
赵庆明老师7 小时前
Vben精讲:21-详解web-antd:tsconfig.json
前端·json·vim
wc887 小时前
微软EDGE浏览器功能学习
前端·学习·edge