前端框架中 “类mixin” 模式的思考
“类 mixin” 指的是 Vue 中的 mixin,Regular 中的 implement
使用 Mixin 的目的
首先我们需要知道为什么会有 mixin
的存在?
为了扩展对象(组件)的功能
扩展对象功能的需求是很容易的理解的。比如业务开发时会碰到跨模块传递消息的需求,常用的方法是使用 “发布-订阅模式” 来创建一个全局的
EventEmitter
。不使用mixin
时的使用方法如下
// global/eventEmitter class EventEmitter {
on(eventName, handle) { } emit(eventName) { }
} // ComponentA
import EventEmitter from 'global/eventEmitter'; // 全局的 EventEmitter 对象 class ComponentA {
constructor() {
EventEmitter.on('event', () => {});
}
} // ComponentB
import EventEmitter from 'global/eventEmitter'; class ComponentB {
constructor() {
EventEmitter.emit('event');
}
}
我们需要在不同的组件中引入
EventEmitter
来使用它如果使用
mixin
的话,我们可以这样做
// eventEmitter mixin
import EventEmitter from 'global/eventEmitter'; // 全局的 EventEmitter 对象 const eventEmitterMixin = {
on: (eventName, handle) => {EventEmitter.on(eventName, handle)},
fire: () => {EventEmitter.emit(eventName)}
} // Root Component
Component.mixin(eventEmitterMixin); // ComponentA
class ComponentA {
constructor() {
this.on('event', () => {});
}
} // ComponentB
class ComponentB {
constructor() {
this.emit('event');
}
}
这样通过
mixin
来扩展了组件的功能,是每个组件都可以方便的使用EventEmitter
的功能- 为了复用代码
软件开发中的
DRY
原则还是有必要遵守的。过多的重复代码会导致维护上的麻烦,通过mixin
,我们可以在不同的对象上使用同一份代码来完成相同的功能,减轻我们维护的压力。
复用 VS 扩展
其实这两个没有可比性,但在我们决定是否需要将一个对象通过 mixin
的方式混入到其他对象时就应该考虑这个问题。
原则上 复用 > 扩展。
如果一个 mixin
只是为了扩展单个对象的功能,而扩展的功能并不能复用到其他的对象时,就不应该使用 mixin
,而是直接写在那个对象上更好。
如果扩展的功能可以被复用的话,那么可以考虑使用 mixin
。
mixin 的缺点
mixins-considered-harmful 这篇文章已经列举了一些问题,我简单的列举下
mixin
会引入隐性的依赖关系mixin
会导致命名冲突mixin
会增加项目的复杂性
如何正确的使用 Mixin
虽然
mixin
有一些缺点,但正确的使用还是可以方便我们的开发没有不合理的设计模式,只有不合理的使用设计模式
首先我们需要解决混入的 mixin
可能会造成隐性的依赖关系,而形成这种依赖关系多半是 mixin
中的扩展功能依赖了被扩展对象想内部数据,例如:
// 一个数据库查看组件
class DatabaseView {
state = {
database: [{name: 'db1', id: 1, tables: [{name: 'table1', id: 1}]}]
}
}
DatabaseView.mixin(viewTabelDetails);
// 把查看表详情弹窗作为 mixin 混入
const mixin = {
viewTabelDetails: (dbId, tableId) => {
const db = this.state.database.filter(db => db.id === dbId)[0];
if (db) {
const table = db.tables.filter(table => table.id === tableId)[0];
if (table) {
Model.show(table);
}
}
}
}
上面的例子中,mixin
依赖的 DarabaseView
中的 database
数据。这就导致了如果页面中其他的组件也需要一个查看表详情弹窗的功能,那么这个组件也必须有类似的 database
数据,形成了一个隐性的依赖关系。
避免的方式就是 mixin
对象中的功能不要与被扩展对象发生依赖,而在组件开发中这个依赖多半就是使用了被扩展对象的 state
产生的
至于命名冲突和增加项目的复杂性可以通过其他的方式解决,相比于上面的问题还算简单
总结
mixin
只是用来扩展对象功能的,而且这个扩展功能是可以被复用的,否则你应该直接写在对象里面- 扩展功能的同时,
mixin
提供的函数不应该依赖被扩展对象的内部数据。因为如果依赖的被扩展对象的内部数据,会使这个mixin
只能被包含特定数据对象的对象复用,影响mixin
的复用
个人主观观点
其实我觉得在前端的开发中,我们应该避免使用 mixin
去扩展组件的功能
例如我们完全可以使用函数调用(显性的)去调用 mixin
对象中的方法,而不是一股脑的将 mixin
对象混合到组件中
每次修改使用了 implement
组件都会特别痛苦(这样导入的方法 WebStorm 根本不识别),极大了增加维护的工作量。同时由于有的 mixin
对象依赖的被扩展对象的内部数据,导致想复用的话还得有相同的数据结构(那还复用个锤子啊)
所以,不要用 mixin
!!!
更多文章可以查看本人的博客 https://lleohao.github.io
来源:https://segmentfault.com/a/1190000017554489
前端框架中 “类mixin” 模式的思考的更多相关文章
- 制作类似ThinkPHP框架中的PATHINFO模式功能(二)
距离上一次发布的<制作类似ThinkPHP框架中的PATHINFO模式功能>(文章地址:http://www.cnblogs.com/phpstudy2015-6/p/6242700.ht ...
- 制作类似ThinkPHP框架中的PATHINFO模式功能
一.PATHINFO功能简述 搞PHP的都知道ThinkPHP是一个免费开源的轻量级PHP框架,虽说轻量但它的功能却很强大.这也是我接触学习的第一个框架.TP框架中的URL默认模式即是PathInfo ...
- Web前端开发中的MCRV模式(转)
作者: izujian 来源: baiduux 摘要:针对前端开发中基于ajax的复杂页面开发所面临的代码规模大,难以组织和维护,代码复用性.扩展性和适应性差等问题,本文尝试以MVC思想为 基础,结 ...
- PythonI/O进阶学习笔记_3.2面向对象编程_python的继承(多继承/super/MRO/抽象基类/mixin模式)
前言: 本篇相关内容分为3篇多态.继承.封装,这篇为第二篇 继承. 本篇内容围绕 python基础教程这段: 在面向对象编程中,术语对象大致意味着一系列数据(属性)以及一套访问和操作这些数据的方法.使 ...
- 使用appframework前端框架中输入框圆角问题
目前使用HTML5技术来开发手机跨平台app已经成为了曾经的web开发人员介入移动开发的一条捷径.与此对应也出现了很多新的技术来支撑这样的开发方式,例如国外的phonegap和国内的APPcan等.很 ...
- angular中的MVVM模式
在开始介绍angular原理之前,我们有必要先了解下mvvm模式在angular中运用.虽然在angular社区一直将angular统称为前端MVC框架,同时angular团队也称它为MVW(What ...
- 漫谈 GOF 设计模式在 Spring 框架中的实现
原文地址:梁桂钊的博客 博客地址:http://blog.720ui.com 欢迎关注公众号:「服务端思维」.一群同频者,一起成长,一起精进,打破认知的局限性. 漫谈 GOF 设计模式在 Spring ...
- 设计模式在 Spring 框架中的良好应用
在开始正文之前,请你先思考几个问题: 你项目中有使用哪些 GOF 设计模式 说一说 GOF 23 种设计模式的设计理念 说说 Spring 框架中如何实现设计模式 假设我是面试官问起了你这些面试题,你 ...
- day97:MoFang:移动端APP开发准备&移动端项目搭建&APICloud前端框架
目录 1.移动端开发相关概念 1.APP类型 2.移动端屏幕介绍 3.移动端自适配方案 4.元信息(meta) 2.APP开发准备 1.注册APPCLoud账号 2.下载APP开发编辑器 3.下载AP ...
随机推荐
- ch5 vlsms
Variabel Length Subnet Mask vlsms 较早的路由协议 ripv1 没有为子网准备的字段,子网信息会被丢失. 这意味着如果一个路由器运行着一个rip协议具有一个确定的子网掩 ...
- OSG在VS2008下的配置安装
一.准备工作 下载相关的工具软件: 1, 最新版的OSG库:OpenSceneGraph-2.8.2.zip. 2, 安装源代码所需要的工具:cmake-2.6.4-win32-x86.zip 3, ...
- Js中获取时间 new date()的用法
Js中获取时间 new date()的用法 获取时间: var myDate = new Date();//获取系统当前时间 myDate.getYear(); //获取当前年份(2位) myDate ...
- Cyclic GCDs
Cyclic GCDs 题目链接 题面描述 有\(n\)个点,每个点有权值. 现有排列\(P\),\(p_i\)表示\(i\)个点向\(p_i\)连了一条边. 显然会形成若干个简单环.每个简单环的权值 ...
- js身份证号码验证(小程序版)
参考知乎专栏文章https://zhuanlan.zhihu.com/p/22949023 <view class='bgw'> <form> ...... <view ...
- Python,anaconda及pycharm安装过程笔记
1.Python Python有2.X和3.X版本,可以在Windows系统下共存.方法为:Windows下Python多版本共存 可参考: Python及pycharm安装 安装Python后可在c ...
- gulp的安装以及less插件安装与使用
1.安装node.js 下载地址:http://nodejs.cn/download/ 这时我们输入 node -v 以及 npm -v 检查是否安装成功. 2.为了提高后续使用的快速,我们安装 ...
- 关于Python脚本开头两行的:#!/usr/bin/python和# -*- coding: utf-8 -*-的作用 – 转
#!/usr/bin/python 是用来说明脚本语言是python的 是要用/usr/bin下面的程序(工具)python,这个解释器,来解释python脚本,来运行python脚本的. # -*- ...
- oracle基础学习(1)
-解锁用户,需要使用dba权限conn sys/1234 as dba; alert user scott account unlock;/ --initcap方法,实现字符串首字符大写,其余字符小写 ...
- 自定义事件javascript
自定义事件 1.event构造函数自定义事件 /* * 自定义一个名为build的事件 * bubbles :事件是否冒泡 * cancelable:是否阻止事件的默认操作 * composed:指示 ...