分类

工厂模式一般分为:简单工厂模式、工厂方法模式、抽象工厂模式。三种模式从上到下逐步抽象,一般也把简单工厂模式看为工厂方法模式的一种特例。

简单工厂

工厂模式 - 图1我们先分析一下简单工厂的UML图,途中有以下几个角色

  1. 工厂类角色(SimpleFactory):核心类根据逻辑不同,产生具体的工厂产品
  2. 抽象产品(AbstractProduct):它一般是具体产品继承的父类或者实现的接口。由接口或者抽象类来实现。
  3. 具体产品(ConcreteProduct):工厂类所创建的对象就是此角色的实例

假设当前的业务场景,需要对外提供通用的自定义提示Alert,Confirm,Prompt。三种提示都有通用的show方法。

  1. // 抽象产品
  2. class CommonNotice () {
  3. show () {}
  4. close () { // this function will close the notice for all instance}
  5. }
  6. // 具体产品1:Alert
  7. class CommonAlert extends CommonNotice () {
  8. show () {console.log('i am alert')}
  9. }
  10. // 具体产品2:Confirm
  11. class CommonConfirm extends CommonNotice () {
  12. show () {console.log('i am confirm')}
  13. }
  14. // 具体产品3:Confirm
  15. class CommonPrompt extends CommonNotice () {
  16. show () {console.log('i am Prompt')}
  17. }
  18. // 工厂类角色
  19. function SimpleFactory name) {
  20. switch (name) {
  21. case 'alert' return new CommonAlert();
  22. case 'confirm' return new CommonConfirm();
  23. case 'prompt' return new CommonPrompt();
  24. }
  25. }
  26. // 使用工厂
  27. var factoryClient = SimpleFactory('alert')
  28. factoryClient.show() // this will call show funciton in CommonAlert

优点

  1. 简单工厂包含必要的判断逻辑,简单工厂实现了对象的创建和使用的分离。
  2. 客户端无需知道所创建的具体产品类的类名,只需要具体产品类对应的参数即可。
  3. 在不修改任何客户端代码的情况下更换和增加新的具体产品类,在一定程度上提高了系统的灵活性。

    缺点

  4. SimpleFactory的职责过重,它包含核心的逻辑判断语句,它一旦有问题,整个系统都要出问题。

  5. 在添加新的类的时候,SimpleFactory就要修改,违反了开放——封闭原则!这样及其不利于系统的扩展和维护。

    工厂方法

    简单工厂模式中存在一个问题,如果需要添加一个新的产品,那必须要修改SimpleFactory工厂类,一旦操作不当,在修改时就有可能引发更多的问题。参考开闭原则的规定,我们希望新的扩展不需要对原有的代码进行修改。

工厂模式 - 图2相比简单工厂模式,我们多了抽象工厂(AbstractFactory)和具体工厂(concreteFactory)

  1. // 抽象产品
  2. class CommonNotice {
  3. show () {}
  4. close () {
  5. // this function will close the notice for all instance
  6. }
  7. }
  8. // 具体产品1:Alert
  9. class CommonAlert extends CommonNotice {
  10. show () {console.log('i am alert')}
  11. }
  12. // 具体产品2:Confirm
  13. class CommonConfirm extends CommonNotice {
  14. show () {console.log('i am confirm')}
  15. }
  16. // 具体产品3:Confirm
  17. class CommonPrompt extends CommonNotice {
  18. show () {console.log('i am Prompt')}
  19. }
  20. // 抽象工厂
  21. class AbstractFactory {
  22. // 工厂方法
  23. createProduct () {}
  24. }
  25. // 具体工厂1
  26. class AlertFactory extends AbstractFactory {
  27. createProduct () {
  28. return new CommonAlert()
  29. }
  30. }
  31. // 具体工厂2
  32. class ConfirmFactory extends AbstractFactory {
  33. createProduct () {
  34. return new CommonConfirm()
  35. }
  36. }
  37. // 具体工厂3
  38. class PromptFactory extends AbstractFactory {
  39. createProduct () {
  40. return new CommonPrompt()
  41. }
  42. }
  43. // 使用Alert 我们通过createProduct这个工厂方法来获取实际需要调用的对象实例
  44. var client = (new AlertFactory()).createProduct()
  45. client.show() // i am alert
  46. // 如果添加了一个CommonMessage的实现
  47. // 具体产品:Confirm
  48. class CommonMessage extends CommonNotice {
  49. show () {console.log('i am message')}
  50. }
  51. // 具体工厂
  52. class MessageFactory extends AbstractFactory {
  53. createProduct () {
  54. return new CommonMessage()
  55. }
  56. }
  57. // 使用
  58. var client2 = (new MessageFactory()).createProduct()
  59. client.show() // i am message

优点

  1. 工厂方法用来创建客户所需要的产品,同时隐藏了哪种具体产品类将被实例化的细节,用户只需要要关注工厂,不需要关注创建的细节。
  2. 在增加修改新的运算类的时候不用修改代码,只需要增加对应的工厂就好,完全符合开放——封闭性原则。

    缺点

  3. 在增加新的产品时,也必须增加新的工厂类,会带来额外的开销

  4. 抽象层的加入使得理解程度加大

    抽象工厂

    抽象工厂封装类一组具有共同目标的单个工厂,比如alert、message、prompt、confirm都需要实现各自的show方法。它能够将一组对象的实现细节分离出来,允许多种对象类型一起工作。 ```javascript // 抽象工厂类 var AbstractFactory = (function () { var types = {} return { // 提供注册产品的方法 registerNotice: function (type, Notice) { var proto = Notice.prototype; // 只要具体产品实现了统一契约show方法即可 if (proto.show) {
    1. types[type] = Notice
    } }, // 获取具体产品 getNotice: function (type) { var Notice = types[type]
    1. if (Notice) {
    2. return new Notice()
    } else {
    1. return null
    } } } })(); AbstractFactory.registerNotice(‘Alert’, CommonAlert) AbstractFactory.registerNotice(‘Confirm’, CommonConfirm) AbstractFactory.registerNotice(‘Prompt’, CommonPrompt)

// client使用 AbstractFactory.getNotice(‘Alert’).show() AbstractFactory.getNotice(‘Confirm’).show() AbstractFactory.getNotice(‘Prompt’).show()

// 当后续需要扩展产品 // 新增具体产品 class CommonModal { show () { // modal show function } } AbstractFactory.registerNotice(‘Modal’, CommonModal)

```

优点

  1. 符合开闭原则
  2. 减少工厂方法中具体工厂类的开销

    缺点

    留给大家自己去实践

参考

[1]Addy Osmani著 徐涛译.JavaScript设计模式.北京:人民邮电出版社,2013,6
[2]https://blog.csdn.net/xiao1_1bing/article/details/81774931
[3]https://blog.csdn.net/jerry11112/article/details/80618420