目录
3、存储N个用户信息+不同年龄用户有不同美食的搭配方案【简单工厂模式】
本文是小编阅读《JavaScript 设计模式核心原理与应用实践》这本书,记录的学习笔记,更多详细知识可以直接阅读原文
JavaScript 设计模式核心原理与应用实践——掘金小册https://juejin.cn/book/6844733790204461070/section/6844733790246404109首要任务:认识哪些是变与不变
通过实现用户需求举例
- // 原始对象
- const obj = {
- id:1,
- name:'sxx',
- age:19,
- sex:1
- }
- console.log(obj);
- // 简单构造器
- class User{
- constructor(id,name,age,sex){
- this.id = id
- this.name = name
- this.age = age
- this.sex = sex
- }
- }
- // 调用简单构造器
- const me = new User(1,'sxx',19,1);
- const you = new User(2,'张三',66,0);
- console.log(me,you);
在创建一个user过程中,谁变了,谁不变?
很明显,变的是每个user的姓名、年龄这些值,这是用户的个性,不变的是每个员工都具备姓名、年龄、工种这些属性,这是用户的共性。
(1)笨方法
- // 一个一个构建构造器【笨方法】
- class Young{
- constructor(id,name,sex){
- this.id = id
- this.name = name
- this.age = 19
- this.sex = sex
- this.food = ['汉堡','炸鸡','可乐']
- }
- }
- class Old{
- constructor(id,name,sex){
- this.id = id
- this.name = name
- this.age = 99
- this.sex = sex
- this.food = ['稀饭','青菜','荔枝肉']
- }
- }
- function Factory(id,name,age,sex){
- switch(age){
- case 19:
- return new Young(id,name,sex)
- case 99:
- return new Old(id,name,sex)
- }
- }
- const me = Factory(1,'sxx',19,1)
- const you = Factory(2,'张三',99,0)
- console.log(me,you);
(2)灵活方法
- // 观察变与不变【灵活方法】
- class User{
- constructor(id,name,age,sex,food){
- this.id = id
- this.name = name
- this.age = age
- this.sex = sex
- this.food = food
- }
- }
- function Factory(id,name,age,sex){
- let food
- switch(age){
- case 3:
- food = ['奶粉','米糊']
- break
- case 19:
- food = ['汉堡','炸鸡','可乐']
- break
- case 99:
- food = ['稀饭','青菜','荔枝肉']
- break
- }
- return new User(id,name,age,sex,food)
- }
- console.log(Factory(1,'baby',3,0));
- console.log(Factory(2,'sxx',19,1));
- console.log(Factory(3,'张三',99,0));
新的需求:
①推出普通、豪华、至尊等套餐,不同年龄用户能够自主选择套餐
②拓展功能:供服务员、厨师、老板等使用
以上需求,每一次都要回去修改 Factory 的函数体,Factory会变得异常庞大——没有遵守开放封闭原则
开放封闭原则:对拓展开放,对修改封闭。软件实体(类、模块、函数)可以扩展,但是不可修改
举例:制造智能手机
已知:
①智能手机的基本组成操作系统和硬件
②二者条件兼顾才能实现量产
③二者不同的厂商并不知道下一个生产线具体要生产的设计
解决措施:
写一个抽象类,约定某手机的基本组成
- class MobilePhoneFactory {
- // 提供操作系统的接口
- createOS(){
- throw new Error("抽象工厂方法不允许直接调用,你需要将我重写!");
- }
- // 提供硬件的接口
- createHardWare(){
- throw new Error("抽象工厂方法不允许直接调用,你需要将我重写!");
- }
- }
(1)以上类,除了约定手机流水线的通用能力之外,啥也不干。如果让它干点啥,比如 new 一个 MobilePhoneFactory
实例,并尝试调用它的实例方法,它将报错
(2)在抽象工厂模式中,以上类就是食物链顶端最大的Boss
当明确了生产方案:抽象工厂不工作,具体工厂来工作
举例:一个专门生产 Android 系统 + 高通硬件的手机(FakeStar)的生产线
(1)定制一个具体工厂
- // 具体工厂继承自抽象工厂
- class FakeStarFactory extends MobilePhoneFactory {
- createOS() {
- // 调用AndroidOS()构造函数,提供安卓系统实例
- return new AndroidOS()
- }
- createHardWare() {
- // 调用QualcommHardWare()构造函数,提供高通硬件实例
- return new QualcommHardWare()
- }
- }
①两个构造函数:AndroidOS 和 QualcommHardWare,分别用于生成具体的操作系统和硬件实例像这种被用于 new 出具体对象的类,叫做具体产品类(ConcreteProduct)
②具体产品类往往不会孤立存在,不同的具体产品类往往有着共同的功能,比如安卓系统类和苹果系统类,它们都是操作系统,都有着可以操控手机硬件系统这样一个最基本的功能
③因此我们可以用一个抽象产品(AbstractProduct)类来声明这一类产品应该具有的基本功能
(2)抽象产品类
- // 定义操作系统这类产品的抽象产品类
- class OS {
- controlHardWare() {
- throw new Error('抽象产品方法不允许直接调用,你需要将我重写!');
- }
- }
-
- // 定义具体操作系统的具体产品类
- class AndroidOS extends OS {
- controlHardWare() {
- console.log('我会用安卓的方式去操作硬件')
- }
- }
-
- class AppleOS extends OS {
- controlHardWare() {
- console.log('我会用🍎的方式去操作硬件')
- }
- }
- ...
(3)硬件类产品
- // 定义手机硬件这类产品的抽象产品类
- class HardWare {
- // 手机硬件的共性方法,这里提取了“根据命令运转”这个共性
- operateByOrder() {
- throw new Error('抽象产品方法不允许直接调用,你需要将我重写!');
- }
- }
-
- // 定义具体硬件的具体产品类
- class QualcommHardWare extends HardWare {
- operateByOrder() {
- console.log('我会用高通的方式去运转')
- }
- }
-
- class MiWare extends HardWare {
- operateByOrder() {
- console.log('我会用小米的方式去运转')
- }
- }
- ...
(4)生产一台FakeStar手机
- // 这是我的手机
- const myPhone = new FakeStarFactory()
- // 让它拥有操作系统
- const myOS = myPhone.createOS()
- // 让它拥有硬件
- const myHardWare = myPhone.createHardWare()
- // 启动操作系统(输出‘我会用安卓的方式去操作硬件’)
- myOS.controlHardWare()
- // 唤醒硬件(输出‘我会用高通的方式去运转’)
- myHardWare.operateByOrder()
此时我们不需要对抽象工厂MobilePhoneFactory做任何修改,只需要拓展它的种类
这样对原有的系统不会造成任何潜在影响,即“对拓展开放,对修改封闭”
- class newStarFactory extends MobilePhoneFactory {
- createOS() {
- // 操作系统实现代码
- }
- createHardWare() {
- // 硬件实现代码
- }
- }
(1)抽象工厂和简单工厂有哪些异同?
①共同点:尝试去分离一个系统中变与不变的部分
②不同点:场景的复杂度
简单工厂:处理容易抽离的类
逻辑本身比较简单,故而不苛求代码可扩展性。
抽象工厂:处理非常棘手、繁杂的类
这些类中不仅能划分出门派,还能划分出等级,同时存在着千变万化的扩展可能性
这使得我们必须对共性作更特别的处理、使用抽象类去降低扩展的成本,同时需要对类的性质作划分
(2)四个关键角色
(3)学习注意点
①学会用 ES6 模拟 JAVA 中的抽象类
②了解抽象工厂模式中四个角色的定位与作用
③对“开放封闭原则”形成自己的理解,知道它好在哪,知道执行它的必要性