理解工厂模式

Posted by AceKei on May 7, 2019

是什么

Define an interface for creating an object, but let subclasses decide which class to instantiate. Factory Method lets a class defer instantiation to subclasses.

创建型模式。在基类中定义一个创建对象的接口,并且让子类选择实例化哪个类。工厂方法允许类将实例化延迟到子类。

工厂模式的分类

  • Factory Method,工厂方法模式。
  • Abstract Factory,抽象工厂模式。

优缺点

优点:

解耦:把对象的创建和使用的过程分开。既只负责对象的创建,对象是怎么使用的,就不关我的事了。 降低代码的重复性:如果创建一个对象比较复杂,但是许多地方需要使用到对象,那么就会有许多重复的代码。 降低维护成本:由于工厂模式只负责对象的创建,所以当业务逻辑发生变化时,不需要修改所有创建该对象的类,只需要在创建的逻辑里面修改即可。

工厂方法模式

在基类的编程中,工厂方法模式是一种创建型模式,它使用工厂方法来处理创建对象的问题,而无需指定确切的类。这是通过调用工厂方法创建对象来完成的,也就是在接口中指定并由子类实现,或者在基类中实现并由子类覆盖,而不是通过调用构造函数。

例子

铁匠铸造兵器,精灵需要精灵类的兵器,并且兽人也需要兽人类的兵器。根据相应的种族选择相应的铁匠来铸造兵器。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
//铁匠
public interface Blacksmith {
  Weapon manufactureWeapon(WeaponType weaponType);
}

//兵器
public interface Weapon {
    
}

//精灵兵器
public class ElfWeapon implements Weapon{
    
}

//兽人兵器
public class OrcWeapon implements Weapon{
    
}

//制作精灵兵器的铁匠
public class ElfBlacksmith implements Blacksmith {
  public Weapon manufactureWeapon(WeaponType weaponType) {
    return new ElfWeapon(weaponType);
  }
}

//制作兽人兵器的铁匠
public class OrcBlacksmith implements Blacksmith {
  public Weapon manufactureWeapon(WeaponType weaponType) {
    return new OrcWeapon(weaponType);
  }
}

现在根据需要选择相应的铁匠

1
2
3
4
5
6
7
//精灵
Blacksmith blacksmith = new ElfBlacksmith();
//兵器-枪
blacksmith.manufactureWeapon(WeaponType.SPEAR);
//兵器-盾
blacksmith.manufactureWeapon(WeaponType.SHIELD);
//兽人同理

应用

  • 一个类不知道它所需要的对象的类,在工厂模式中,客户端不需要知道具体产品类的类名,只需要知道对应的工厂即可,具体的产品对象由具体的工厂创建,但是客户端需要知道创建具体产品是哪个工厂类。
  • 一个类通过其子类来指定创建哪个对象,在工厂模式中,对于抽象工厂类只需要提供一个创建产品的接口,而由其子类来确定具体要创建哪个对象。
  • 将创建的对象委托给多个工厂子类的某一个,客户端在使用时,不需要关心是哪一个工厂子类在创建产品子类,需要时动态指定,可以将具体的工厂类的类名存储在配置文件或者数据库中。

工厂方法模式角色分配

  • 抽象工厂角色:是工厂模式的核心,与应用程序无关。任何在模式中创建的对象的工厂类必须实现该接口。
  • 具体工厂角色:抽象工厂类的具体实现,包含着与应用程序相关的逻辑。
  • 抽象产品角色:产品对象的共同父类或共同拥有的接口。
  • 具体产品对象:实现了抽象产品角色所定义的接口。某具体产品有专门的具体工厂创建,它们之间往往一一对应

java中的应用

  • java.util.Calendar
  • java.util.ResourceBundle
  • java.text.NumberFormat
  • java.nio.charset.Charset
  • java.net.URLStreamHandlerFactory
  • java.util.EnumSet
  • javax.xml.bind.JAXBContext

抽象工厂模式

提供用于创建相关或从属对象族的接口,而无需指定其具体类。

抽象工厂模式是工厂方法模式的进一步深化,在抽象工厂模式中,工厂类不仅可以创建一种产品,还能创建一组产品。

例子

现在有一组产品:城堡,国王,军队。

现在有2个国家:精灵和兽人。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
//城堡
public interface Castle {
  String getDescription();
}
//国王
public interface King {
  String getDescription();
}
//军队
public interface Army {
  String getDescription();
}

//精灵的实现
// Elven implementations ->
public class ElfCastle implements Castle {
  static final String DESCRIPTION = "This is the Elven castle!";
  @Override
  public String getDescription() {
    return DESCRIPTION;
  }
}
public class ElfKing implements King {
  static final String DESCRIPTION = "This is the Elven king!";
  @Override
  public String getDescription() {
    return DESCRIPTION;
  }
}
public class ElfArmy implements Army {
  static final String DESCRIPTION = "This is the Elven Army!";
  @Override
  public String getDescription() {
    return DESCRIPTION;
  }
}

//兽人的实现同理
// Orcish implementations similarly...

接下来精灵和兽人王国将要包含城堡,国王,军队。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
//王国工厂
public interface KingdomFactory {
  Castle createCastle();
  King createKing();
  Army createArmy();
}

//精灵王国
public class ElfKingdomFactory implements KingdomFactory {
  public Castle createCastle() {
    return new ElfCastle();
  }
  public King createKing() {
    return new ElfKing();
  }
  public Army createArmy() {
    return new ElfArmy();
  }
}

//兽人王国
public class OrcKingdomFactory implements KingdomFactory {
  public Castle createCastle() {
    return new OrcCastle();
  }
  public King createKing() {
    return new OrcKing();
  }
  public Army createArmy() {
    return new OrcArmy();
  }
}

工厂有了,现在开始建造精灵王国

1
2
3
4
5
6
7
8
KingdomFactory factory = new ElfKingdomFactory();
Castle castle = factory.createCastle();
King king = factory.createKing();
Army army = factory.createArmy();

castle.getDescription();  // Output: This is the Elven castle!
king.getDescription(); // Output: This is the Elven king!
army.getDescription(); // Output: This is the Elven Army!

此外,我们还可以设计不同的工厂来实现不同的具体工厂。 通过枚举和switch来区分具体工厂实现。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
public static class FactoryMaker {

  public enum KingdomType {
    ELF, ORC
  }

  public static KingdomFactory makeFactory(KingdomType type) {
    switch (type) {
      case ELF:
        return new ElfKingdomFactory();
      case ORC:
        return new OrcKingdomFactory();
      default:
        throw new IllegalArgumentException("KingdomType not supported.");
    }
  }
}

public static void main(String[] args) {
  App app = new App();

  LOGGER.info("Elf Kingdom");
  app.createKingdom(FactoryMaker.makeFactory(KingdomType.ELF));
  LOGGER.info(app.getArmy().getDescription());
  LOGGER.info(app.getCastle().getDescription());
  LOGGER.info(app.getKing().getDescription());

  LOGGER.info("Orc Kingdom");
  app.createKingdom(FactoryMaker.makeFactory(KingdomType.ORC));
  -- similar use of the orc factory
}

应用

  • 和工厂方法一样客户端不需要知道它所创建的对象的类
  • 需要一组对象共同完成某种功能时,并且可能存在多组对象完成不同功能的情况。(同属于同一个产品族的产品)
  • 系统结构稳定,不会频繁的增加对象。(因为一旦增加就需要修改原有代码,不符合开闭原则)

工厂方法模式角色分配

  • 抽象工厂角色:是工厂模式的核心,与应用程序无关。任何在模式中创建的对象的工厂类必须实现该接口。
  • 具体工厂角色:抽象工厂类的具体实现,包含着与应用程序相关的逻辑。
  • 抽象产品角色:产品对象的共同父类或共同拥有的接口。
  • 具体产品对象:实现了抽象产品角色所定义的接口。在抽象工厂中创建的产品属于同一产品族,这不同于工厂模式中的工厂只创建单一产品。

java中的应用

javax.xml.parsers.DocumentBuilderFactory javax.xml.transform.TransformerFactory javax.xml.xpath.XPathFactory

参考

  • https://github.com/iluwatar/java-design-patterns/tree/master/abstract-factory
  • https://github.com/iluwatar/java-design-patterns/tree/master/factory-method
  • https://segmentfault.com/a/1190000015050674