设计模式-解决软件开发中最常见问题的方法。在本文中,我们将参考《权力的游戏》研究生成模式。在此处阅读有关结构模式的信息。生成模式旨在与用于构造对象的机制一起使用,以便在这种情况下以最合适的方式创建对象。最常见的生成方式如下:- 工厂(面料)
- 抽象(抽象)
- 构造函数(Builder)
- 原型(Prototype)
- 单身人士(单身人士)
厂
工厂是一种模式,它使用所谓的工厂方法来创建对象,而无需确定所创建对象的类。这是什么意思?想象一下,我们希望能够创建士兵。这些士兵可以来自塔加里安之家,也可以来自兰尼斯特之家。为此,我们需要:- 定义士兵的界面
- 每种士兵都有一个阶级,可以赋予每个家庭权力
- 要求创建新士兵的阶级,无论他属于哪个房屋
class Soldier {
constructor(name) {
this.name = name
this.attack = this.attack.bind(this)
}
attack() {}
}
class LannisterSoldier extends Soldier {
attack() {
return 'Lannister always pays his debts'
}
}
class TargaryenSoldier extends Soldier {
attack() {
return 'Fire and blond'
}
}
class Spawn {
constructor(type, name) {
if (type === 'lannister') return new LannisterSoldier(name)
else return new TargaryenSoldier(name)
}
}
(() => {
const lannister = new Spawn('lannister', 'soldier1')
const targaryen = new Spawn('targaryen', 'soldier2')
console.log(lannister.attack())
console.log(targaryen.attack())
})()
什么时候使用?
免责声明:基于对象的抽象模板。在函数式编程中很难使用。该模板使您可以封装一组执行类似任务的单个工厂,而无需定义特定的类。在标准使用中,客户端软件创建抽象工厂的特定实现,然后使用通用工厂接口创建特定对象,作为单个系统的一部分。客户不知道(或对他不重要)他从每个内部工厂收到的特定对象,因为为此使用了公共接口。想象一下,我们要单独管理每个房屋。每个房屋都应有机会确定王位继承人和他的挚爱。为此,我们需要:
class HeirToTheThrone {
conctructor(name, isActualOnTheThrone) {
this.name = name
this.isActualOnTheThrone = isActualOnTheThrone
this.getTheThrone = this.getTheThrone.bind(this)
}
getTheThrone() {}
}
class HeirToTheThroneLannister extends HeirToTheThrone {
getTheThrone(){
console.log('kill all')
}
}
class HeirToTheThroneTargaryen extends HeirToTheThrone {
getTheThrone() {
console.log('burn all')
}
}
class Subject {
constructor(name) {
this.name = name
this.speak = this.speak.bind(this)
}
speak() {}
}
class SubjectLannister extends Subject {
speak(){
console.log('i love Cersei')
}
}
class SubjectTargaryen extends Subject {
speak(){
console.log('i love Daenerys')
}
}
class House {
constructor() {
this.getHeir = this.getHeir.bind(this)
this.getSubject = this.getSubject.bind(this)
}
getHeir(){}
getSubject(){}
}
class Lannister extends House {
getHeir() {
return new HeirToTheThroneLannister('Cersei', true)
}
getSubject(name) {
return new SubjectLannister(name)
}
}
class Targaryen extends House {
getHeir() {
return new HeirToTheThroneTargaryen('Daenerys', true)
}
getSubject(name) {
return new SubjectTargaryen(name)
}
}
(()=>{
const lannister = new Lannister()
const targaryen = new Targaryen()
lannister.getHeir().getTheThrone()
lannister.getSubject().speak()
targaryen.getHeir().getTheThrone()
targaryen.getSubject().speak()
})()
?
设计者的目的是将复杂对象与其表示分离。由于对象的复杂性,此模板使您可以通过另一个对象(构造函数)分离创建新对象的过程。想象一下,我们想为每个家庭创建一支舰队。每个家庭将有一定数量的船只和战士。为了便于创建,我们应该能够调用makeNavy方法,该方法将通过设置自动创建我们需要的所有内容。为此,我们需要:- 创建机队的类
- 构造函数定义的接口
- 负责创造我军目标的班级
- 负责创造士兵和船只的班级
class Lannister {
constructor() {
this.soldiers = []
this.ships = []
this.makeNavy = this.makeNavy.bind(this)
}
makeNavy(soldiers, ships) {
const Build = new ConcreteBuilder()
for (let i = 0; i < soldiers; i++) {
this.soldiers.push(Build.createSoldier())
}
for (let i = 0; i < ships; i++) {
this.ships.push(Build.createShip())
}
}
}
class Builder {
createSoldier() {}
createShip() {}
}
class ConcreteBuilder extends Builder {
createSoldier() {
const soldier = new Soldier()
return soldier
}
createShip() {
const ship = new Ship()
return ship
}
}
class Soldier {
constructor() {
console.log('soldier created')
}
}
class Ship {
constructor() {
console.log('ship created')
}
}
(() => {
const lannister = new Lannister()
lannister.makeNavy(100, 10)
})()
什么时候使用?
- 当创建对象的过程非常复杂时,它涉及大量的强制和可选参数
- 当构造函数参数数量的增加导致设计者数量的增加时
- 当客户端期望所构造对象的不同视图时
原型
使用原型,您可以确定通过原型继承创建的对象的类型,并使用现有对象的方案创建新对象。这样可以提高性能并最大程度地减少内存丢失。想象一下,我们想组建一支白人步行者大军。我们对这支部队没有特殊要求。我们只需要它们很多,它们具有相同的特性,并且不会占用很多内存空间。为此,我们需要:- 用于存储有关白步行者信息的类
- 克隆实例的方法返回相同的方法
class WhiteWalker {
constructor(force, weight) {
this.force = force
this.weight = weight
}
clone() {
console.log('cloned')
return new WhiteWalker(this.name, this.weight)
}
}
(()=>{
const firstWalker = new WhiteWalker()
const walkers = [firstWalker]
for(let i=0;i<100;i++){
walkers.push(firstWalker.clone())
}
})()
原型的优缺点
优点:- 通过消除使用新操作员创建新对象的需求,帮助节省成本,时间和生产力
- 降低了初始化对象的复杂性:每个类都使用自己的克隆方法
- 与使用抽象模板时一样,无需分类和创建许多子类来初始化对象
- 通过更改复制对象的某些属性来创建新对象,从而提高系统灵活性
缺点:辛格尔顿
Singleton允许您确保创建的对象是特定类的唯一实例。这样的对象通常用于控制系统中的几种操作。想象一下,我们要确保有一个龙母。为此,我们需要:let INSTANCE = null
class MotherOfDragons {
constructor(name, dragons) {
if(!!INSTANCE) return INSTANCE
this.dragons = dragons
this.name = name
this.getMyDragons = this.getMyDragons.bind(this)
INSTANCE = this
}
getMyDragons(){
console.log(`I'm ${this.name} and my dragons are`, this.dragons)
}
}
(()=>{
const dragonMother = new MotherOfDragons('Daenerys Targaryen', [
'Drogon',
'Rhaegal',
'Viserion'
])
const dragonMother2 = new MotherOfDragons('Cercei Targaryen', [
'Tirion',
'Jennifer',
'Goblin'
])
dragonMother.getMyDragons()
dragonMother2.getMyDragons()
console.log(dragonMother instanceof MotherOfDragons)
console.log(dragonMother2 instanceof MotherOfDragons)
console.log(dragonMother2 === dragonMother)
})()
什么时候使用?
- 当用于创建对象的资源受到限制时(例如,数据库连接对象)
- 最好以单例方式建立授权以提高性能。
- 当您需要创建一个类来配置应用程序时
- 需要为资源分配创建类时
Github
代码。注意 trans:这是一段有关设计模式的精彩视频。感谢您的关注。