在构造我们的对象的时候,很容易出现设计的缺陷,比如严重依赖某个细节实现,或者不符合迪米特法则, 不符合里式替换原则,这些都可以通过简单工单的设计模式解决。
简单通常的设计UML图如下所示:

2、工厂模式(FactoryPattern) - 图1

1、 使用示例

这里我们实现一个非常简单的例子,获取不同颜色的书籍,代码如下:

  • 定义书籍的共性方法,以及其功能

    1. abstract static class Book {
    2. // 描述
    3. public void desc() {
    4. System.out.println("这是一本书");
    5. }
    6. // 获取书籍的颜色
    7. public abstract Color getColor();
    8. // 获取书籍的价格
    9. public abstract float getPrice();
    10. }
  • 根据书籍的定义实现红色书和绿色书

    1. static class GreenBook extends Book {
    2. @Override
    3. public Color getColor() {
    4. return Color.GREEN;
    5. }
    6. @Override
    7. public float getPrice() {
    8. return 123;
    9. }
    10. }
    11. static class RedBook extends Book {
    12. @Override
    13. public Color getColor() {
    14. return Color.RED;
    15. }
    16. @Override
    17. public float getPrice() {
    18. return 124;
    19. }
    20. }

在往常的代码开发中,如果我们需要RedBook,只需要 Book book = new RedBook() 这样的方式客户端对RedBook类严重依赖,没有达到解耦的目的,也简洁的违背了迪米特法则,因为上层代码对Book 的实现有直接关系。所以,这里我们需要抽象一个创建者的对象,也就是我们讨论的工厂对象,定义如下:

  1. // 定义创建者,也就是工程对象
  2. interface Factory {
  3. Book getInstance(String className);
  4. Book getInstance(Class<? extends Book> clazz);
  5. }
  6. // 实现具体工厂
  7. static class ConcreteFactor implements Factory {
  8. private ConcreteFactor() {}
  9. private static Factory factory = new ConcreteFactor();
  10. // 使用单例模式,全局唯一工厂对象
  11. public static Factory getFactory() {
  12. return factory;
  13. }
  14. @Override
  15. public Book getInstance(String className) {
  16. try {
  17. return (Book) Class.forName(className).newInstance();
  18. } catch (Exception e) {
  19. return null;
  20. }
  21. }
  22. @Override
  23. public Book getInstance(Class<? extends Book> clazz) {
  24. try {
  25. return clazz.newInstance();
  26. } catch (Exception e) {
  27. return null;
  28. }
  29. }
  30. }
  • 上层代码逻辑需要使用Book,只需要传递类型或者字符串即可, 比如
  1. public static void main(String[] args) {
  2. // 单例模式获取Factory的实例
  3. Factory factory = ConcreteFactor.getFactory();
  4. // 符合迪米特法则,上层代码不需要直接连接底层代码
  5. Book book = factory.getInstance(RedBook.class);
  6. printBookInfo(book);
  7. book = factory.getInstance(GreenBook.class.getName());
  8. printBookInfo(book);
  9. }
  10. // 里式替换原则
  11. private static void printBookInfo(Book book) {
  12. assert book != null;
  13. System.out.println("书的价格是:" + book.getPrice() + "颜色是:" + book.getColor());
  14. }
  • 程序运行结果
    1. 书的价格是:124.0颜色是:java.awt.Color[r=255,g=0,b=0]
    2. 书的价格是:123.0颜色是:java.awt.Color[r=0,g=255,b=0]

2、多工厂模式

上面的代码中,我们仅仅使用到了一个工厂实例对象。在一些复杂的场景中,创建一个产品对象无比复杂,势必造成代码的巨大,这个时候我们可以精细化工厂,如上面的书籍的示例中,我们可以实现创建红色书籍的工厂 RedBookConcreteFactory & GreenBookConcreteFactory 等,当然也可以创建一个创建工厂的工厂,不过就显然有些冗余了!其类图如下所示:

2、工厂模式(FactoryPattern) - 图2

3、总结

  • 工厂模式非常容易拓展,假如需要蓝色的书籍,我们只需要定义一个 BlueBook 继承 Book 即可;
  • 上层代码不需要知道对象的创建过程,接触模块之间的代码耦合
  • 通过工厂获取的对象均为抽象,不是具体的细节,这显然符合里式替换原则
  • 有的设计模式中,将工厂的创建产品的方法抽象为静态的方法,这种称之为静态工厂的设计模式
  • 事实上也可以通过工厂模式实现单例模式,甚至可以使用Map 实现单例的缓存模型