JavaScript 设计模式之组合模式

组合模式

在我们日常中肯呢个会将一个表单用这种模式来创建

const Car = function () { }
Car.prototype.getName = function () { 
  throw new Error("需要重写该方法")
}
Car.prototype.getPrice = function () {
  throw new Error("需要重写该方法")
}
const Benz = function () { }
// 继承Car
Benz.prototype = new Car()
// 重写getName方法
Benz.prototype.getName = function () {
  return 'Benz'
}
const b = new Benz()
console.log(b.getName()) // Benz
console.log(b.getPrice()) // 需要重写该方法

先写一个基类,再继承该基类

const Benz = function (name, price) {
  Car.call(this)
  this.name = name
  this.price = price
}
Benz.prototype = new Car
Benz.prototype.getPrice = function () {
  return this.price
}
Benz.prototype.getName = function () {
  return this.name
}
const benz = new Benz('奔驰', 50)
console.log(benz.getName()) // 输出:奔驰
console.log(benz.getPrice()) // 输出:50
const bmw = new Benz('宝马', 100)
console.log(bmw.getPrice()) // 输出:100

构建一个 Form 表单

首先我们创建一个基类

定义


const Base = function () { 
  this.children = []
  this.element = null
}
Base.prototype = {
  init: function () {
    throw new Error('必须重写该方法')
  },
  add: function () {
    throw new Error('必须重写该方法')
  },
  remove: function () {
    throw new Error('必须重写该方法')
  },
  get: function () {
    throw new Error('必须重写该方法')
  }
}

接下来创建一个容器


const FormItem = function (id,parent) {
  Base.call(this)
  this.id = id
  this.parent = parent
  this.init()
}
FormItem.prototype = new Base()
FormItem.prototype.init = function () {
  this.element = document.querySelector('#form')
  this.element.id = this.id
}
FormItem.prototype.add = function (child) {
  this.children.push(child)
  this.element.appendChild(child.getDom())
  return this
}
FormItem.prototype.getDom = function () {
  return this.element
}
FormItem.prototype.show = function () { 
  this.parent.appendChild(this. Element)
}

注意,这里的 show 方法就是用来将所有的 dom 追加到页面上

下面创建一系列的 form 相关 item 及一些dom


const FieldsetItem = function (selector, label) {
  Base.call(this)
  this.selector = selector
  this.label = label
  this.init()
}
FieldsetItem.prototype = new Base()
FieldsetItem.prototype.init = function () {
  this.element = document.createElement('fieldset')
  const legend = document.createElement('legend')
  legend.innerHTML = this.label
  this.element.appendChild(legend)
}
FieldsetItem.prototype.add = function (child) {
  this.children.push(child)
  this.element.appendChild(child.getDom())
  return this
}
FieldsetItem.prototype.getDom = function () {
  return this. Element
}


const Group = function () {
  Base.call(this)
  this.init()
}
Group.prototype = new Base()
Group.prototype.init = function () {
  this.element = document.createElement('div')
  this.element.className = 'group'
}
Group.prototype.add = function (child) {
  this.children.push(child)
  this.element.appendChild(child.getDom())
  return this
}
Group.prototype.getDom = function () {
  return this.element
}

const LabelItem = function (name, label) {
  Base.call(this)
  this.name = name
  this.label = label
  this.init()
}
LabelItem.prototype = new Base()
LabelItem.prototype.init = function () {
  this.element = document.createElement('label')
  this.element.innerHTML = this.label
  this.element.htmlFor = this.name
}
LabelItem.prototype.add = function (child) {
  // 这里不需要添加,因为label后面直接跟输入框
  return this
}
LabelItem.prototype.getDom = function () {
  return this.element
}

const InputItem = function (name) {
  Base.call(this)
  this.name = name
  this.init()
}
InputItem.prototype = new Base()
InputItem.prototype.init = function () {
  this.element = document.createElement('input')
  this.element.name = this.name
  this.element.style.marginLeft = '5px'
}
InputItem.prototype.add = function (child) {
  // 这里不需要添加,因为输入框后面直接跟标签
  return this
}
InputItem.prototype.getDom = function () {
  return this.element
}

const CheckboxItem = function (name, value, label) {
  Base.call(this)
  this.name = name
  this.value = value
  this.label = label
  this.init()
}
CheckboxItem.prototype = new Base()
CheckboxItem.prototype.init = function () {
  const span = document.createElement('span')
  this.element = document.createElement('label')
  const input = document.createElement('input')
  input.type = 'checkbox'
  span.innerHTML = this.label
  input.value = this.value
  input.style.marginRight = '5px'
  this.element.appendChild(input)
  this.element.appendChild(span)
}
CheckboxItem.prototype.add = function (child) {
}
CheckboxItem.prototype.getDom = function () {
  return this.element
}

const SpanItem = function (name) {
  Base.call(this)
  this.name = name
  this.init()
}
SpanItem.prototype = new Base()
SpanItem.prototype.init = function () {
  this.element = document.createElement('span')
  this.element.innerHTML = this.name
  this.element.style.marginLeft = '5px'
}
SpanItem.prototype.add = function (child) {
  // 这里不需要添加,因为span前面直接跟输入框
  return this
}
SpanItem.prototype.getDom = function () {
  return this. Element
}

使用 

假使页面中存在 dom 

 <form id="form"></form>
 <div id="content"></div>

js

var form = new FormItem('form', document.querySelector('#content'))
form.add(new FieldsetItem('account', '账号').add(
  new Group().add(
    new LabelItem('user_name', '用户名:')
  ).add(
    new InputItem('user_name')
  ).add(new SpanItem('4 到 6 位数字或字母'))
).add(
  new Group().add(
    new LabelItem('user_pwd', '密&emsp;码:')
  ).add(
    new InputItem('user_pwd')
  ).add(new SpanItem('6 到 12 位数字或字母'))
).add(
  new Group().add(
    new CheckboxItem('remember', true, '是否记住')
  )
))
  .show()

效果

总结 

组合模式能够给我们提供一个清晰的组成结构。组合对象类通过继承同一个父类使其具有统一的方法,这样也方便了我们统一管理与使用,当然此时单体成员与组合体成员行为表现就比较一致了,这也模糊了简单对象与组合对象的区别

本图文内容来源于网友网络收集整理提供,作为学习参考使用,版权属于原作者。
THE END
分享
二维码
< <上一篇
下一篇>>