前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >大话设计模式(二)- 工厂模式

大话设计模式(二)- 工厂模式

作者头像
zhaozhen
发布2021-07-15 10:47:02
5100
发布2021-07-15 10:47:02
举报

大话设计模式(二)- 工厂模式

工厂模式: 用来创建对象的创建型模式,在上一章的ajax封装中,我们利用简单工厂创建了ajax框架,而不用去关注内部实现。这也是工厂模式的好处之一。通过使用工厂方法而不是new关键字及具体类,你可以把所有实例化代码集中在一个位置,可以大大简化更换所用的类或在运行期间动态选择所用的类的工作。

简单工厂

应用场景在上一篇文章给过, 在创建ajax对象时,我们不关注ajax 内部的对象如何实现,通过判断浏览器的类型,case到不同的ajax对象,达到实例集中管理,并不关注内部实现的目的。

以下是简单的工厂的实现代码。

代码语言:javascript
复制
// 工厂方法 
let  factory = function (role) {
function User(obj) {
    this.name = obj.name;
    this.role = obj.role;
}
switch(role) {
    case 'superman':
    return new User({ name: '平台用户', role: ['主页', '登录页'] })
    break;
    case 'man':
    return new User({ name: '游客', role: ['登录页']})
    break;
    default:
    throw new Error('参数错误')
}
}
// 工厂方法创建不同的实例 
let superman = factory('superman');
let man = factory('man');
// 简单工厂的弊端会导致如果需要更多实例需要维护一个超级函数
应用的实际例子
代码语言:javascript
复制
var Dialog = (function(){
  var createNotice = function(){
    return '<div>notice</div>';
  }
  var createToast = function(){
    return '<div>toast</div>';
  }
  var createWarnin = function(){
 return '<div>warnin</div>';
  }
  var Dialog = function(){
 this.element = '';
 this.name = '';
 this.show = function(){
   console.log(this.name + ' is show -> ' + this.element);
 };
  }
  
  return {
 factory: function(arg){
   var _dialog;
   if(arg === 'notice'){
     _dialog = new Dialog();
     _dialog.element = createNotice();
     _dialog.name = 'notice';
     }else if(arg === 'toast'){
     _dialog = new Dialog();
     _dialog.element = createToast();
     _dialog.name = 'toast';
   }else if(arg === 'warnin'){
     _dialog = new Dialog();
     _dialog.element = createWarnin();
     _dialog.name = 'warnin';
   }
   return _dialog;
 }
  }
})();
var notice = Dialog.factory('notice');
var toast = Dialog.factory('toast');
var warnin = Dialog.factory('warnin');
toast.show(); //toast is show -> <div>toast</div>
notice.show(); //notice is show -> <div>notice</div>
warnin.show(); //warnin is show -> <div>warnin</div>

简单工厂的适用场景: 简单、 可穷举的工厂实例。因为工厂的方法足够简单,而一个大型项目中往往需要我们进行大批量的拓展,此时简单工厂已经不符合软件的开闭原则,我们并不是每次都要改实现。

开闭原则:对扩展开放,对修改源码行为关闭。

工厂方法

工厂方法: 是在简单工厂上的再拓展,通过new关键字进行实例的创建,此时在创建时遍会再次执行构造函数 对构造的实例进行初始化。

以下是简单工厂实现一个返回角色权限的例子
代码语言:javascript
复制
// 创建一个工厂方法来返回不同的方法
let factory = function (role) {
    if(this instanceof factory) {
        var s = new this[role]();
        return s;
    } else {
        return new factory(role);
    }
}
// 下一次新增新的特性时只需要在函数上绑定数据即可
factory.prototype = {
    admin: function() {
        this.name = '平台用户';
        this.role = ['登录页', '主页']

    },
    common: function() {
        this.name = '游客';
        this.role = ['登录页']
    },
    test: function() {
        this.name = '测试';
        this.role =  ['登录页', '主页', '测试页'];
        this.test = '我还有一个测试属性哦'
    }
}
// 工厂方法创建
let admin = new factory('admin');
let common = new factory('common');
let test = new factory('test');

此时当我们需要给角色增加新特性,或者增加新角色时,只需要在原型上增加新的角色or 新的方法即可,此时即达到了工厂方法的扩展。

抽象工厂

江湖传言, 没有什么是不能通过增加一个抽象层解决的。所以抽象工厂更像是一个供应链,或者说是一个提供一个大而全功能的百货公司,通过不同需求提供不同工厂产出的货物。

以下是抽象工厂的代码实现 代码源自知乎,https://zhuanlan.zhihu.com/p/55840258

代码语言:javascript
复制
abstract class Department {
  // 初始化name成员,参数属性
  constructor(public name: string){
  }
  printName(): void{
    console.log('Department name: ' + this.name);
  }
  abstract printMeeting(): void; // 必须在派生类中实现
}
class AccountingDepartment extends Department {
  constructor() {
    super('Accounting and Auditing'); // 在派生类的构造函数中必须调用super()
  }
  printMeeting(): void{
    console.log('The Accounting Department meets each Monday at 10am.');
  }
  generateReports(): void{
    console.log('Generating accounting reports...')
  }
}
let department: Department; // 允许创建一个对抽象类型的引用
department = new Department(); // 错误:不能创建一个抽象类的实例
department = new AccountingDepartment(); // 允许对一个抽象子类进行实例化和赋值
department.printName();
department.printMeeting();
department.generateReports(); // 错误:方法在声明的抽象类种不存在

抽象类像是一个百货公司,定义了公司是发展方向,提供的东西,而真正提供供货货源的人可能来自京东 淘宝 拼多多,这是我对抽象工厂的理解。

思考题?

在实际应用场景中,你是否有使用抽象工厂,工厂方法, 简单工厂呢?

昨日算法题答案。
代码语言:javascript
复制
/*
 * @lc app=leetcode.cn id=1 lang=javascript
 *
 * [1] 两数之和
 */

// @lc code=start
/**
 * @param {number[]} nums
 * @param {number} target
 * @return {number[]}
 */
var twoSum = function (nums, target) {
  // 设置容器对象
  var map = {};
  // 遍历数组
  for (let index = 0; index < nums.length; index++) {
    // 当数组中存在
    if (map[target - nums[index]] >= 0) {
      return [map[target - nums[index]], index];
    }
    map[nums[index]] = index;
  }
};

此处使用在对象中找看是否找得到的方式来锁定了数组的下标,采用这种查找的方式在很多求索引的题目中经常会遇到,本次也是一个比较经典的案例。你还有其他的解法吗,欢迎在下方留言哟。

每日一道算法题

给定一个排序的整数数组(升序)和一个要查找的整数target,用O(logn)的时间查找到target第一次出现的下标(从0开始),如果target不存在于数组中,返回-1。

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

本文分享自 微瞰技术 微信公众号,前往查看

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

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

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 大话设计模式(二)- 工厂模式
    • 简单工厂
      • 工厂方法
        • 抽象工厂
          • 每日一道算法题
          相关产品与服务
          容器服务
          腾讯云容器服务(Tencent Kubernetes Engine, TKE)基于原生 kubernetes 提供以容器为核心的、高度可扩展的高性能容器管理服务,覆盖 Serverless、边缘计算、分布式云等多种业务部署场景,业内首创单个集群兼容多种计算节点的容器资源管理模式。同时产品作为云原生 Finops 领先布道者,主导开源项目Crane,全面助力客户实现资源优化、成本控制。
          领券
          问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档