抽象工厂 Abstract Factory
抽象工厂模式是一种创建型设计模式, 它能创建一系列相关的对象, 而无需指定其具体类。
假设我们有一个任务需要获得一些图形Shape,其中:
- 一系列功能:比如生成圆、正方形、三角形。
- 一系列功能的不同风格变体:比如红色、绿色、蓝色等不同颜色的风格来生成圆、正方形、三角形。
你需要根据情况生成一系列某种风格的对象,此外,你也不希望在添加新功能或新风格时修改已有代码(功能和风格相互影响)。根据这个条件,可以将风格和功能作为二维向量生成一个二维矩阵如下所示:
最高层-提供 | 中间层-装配 | 最底层-生成 | ||
颜色工厂接口 | ⊙圆形接口 | ⊡正方形接口 | ◬三角形接口 | |
客户应用端入口 | 工厂功能 | ⊙圆形功能 | ⊡正方形功能 | ◬三角形功能 |
应用配置端 | 红色风格工厂类 | ⊙红圆类 | ⊡红正方类 | ◬红三角类 |
绿色风格工厂类 | ⊙绿圆类 | ⊡绿正方类 | ◬绿三角类 | |
蓝色风格工厂类 | ⊙蓝圆类 | ⊡蓝正方类 | ◬蓝三角类 |
在这个矩阵中,我们可以比较清晰的理解功能与风格:
从列看,图形接口需要为所有图形声明抽象图形接口,然后让所有具体图形类实现这些接口(风格工厂接口也一样)。
从行看,每一个具体风格工厂需要为所有该风格的抽象图形提供一组构建方法(整合相同风格图形),最后由应用配置端根据条件选择哪种不同风格的工厂进行配置,最后提供给客户应用端一个接口。
应用条件
业务需要获得一系列不同风格的基于基础类的变种,需要通过客户提供的不同要求从同一个接口获得不同的变种的情况。
- 基于基础类,针对不同风格工厂都有不同的变种。
- 每个风格工厂装配逻辑是一致的,保证提供给客户的接口是保持统一。
实现流程
-
以不同的产品类型与产品风格生成二位矩阵明确目标
如上面那个表格一样
-
为所有产品声明抽象产品接口。 然后让所有具体产品类实现这些接口。
// 按照表格所述创建一个圆形接口Circle,它的所有不同颜色的产品都需要声明getCircleShapeName()方法 public interface Circle { public String getCircleShapeName(); } // 接口下有三个不同颜色的变种圆类 // 红色圆 public class RedCircle implements Circle{ private String name = "RedCircle"; public String getCircleShapeName(){ String str = String.format("I am %s", name); System.out.println(str); return str; } } // 绿色圆 public class GreenCircle implements Circle{ private String name = "GreenCircle"; public String getCircleShapeName(){ String str = String.format("I am %s", name); System.out.println(str); return str; } } // 蓝色圆 public class BlueCircle implements Circle{ private String name = "BlueCircle"; public String getCircleShapeName(){ String str = String.format("I am %s", name); System.out.println(str); return str; } }
-
声明抽象工厂接口,并且在接口中为所有抽象产品提供一组构建方法。为每种产品风格变体实现一个具体工厂类。
// 按照表格所述创建一个颜色工厂接口ColorFactory,它的所有不同颜色工厂都需要声明getCircleShapeName()方法 public interface ColorFactory { public Circle getCircle(); public Square getSquare(); public Triangle getTriangle(); } // 工厂接口下有三个不同颜色工厂 // 红色工厂 public class RedFactory implements ColorFactory { @Override public Circle getCircle() { return new RedCircle(); } @Override public Square getSquare() { return new RedSquare(); } @Override public Triangle getTriangle() { return new RedTriangle(); } } // 绿色工厂 public class GreenFactory implements ColorFactory { @Override public Circle getCircle() { return new GreenCircle(); } @Override public Square getSquare() { return new GreenSquare(); } @Override public Triangle getTriangle() { return new GreenTriangle(); } } // 蓝色工厂 public class BlueFactory implements ColorFactory { @Override public Circle getCircle() { return new BlueCircle(); } @Override public Square getSquare() { return new BlueSquare(); } @Override public Triangle getTriangle() { return new BlueTriangle(); } }
-
在应用程序中开发初始化代码。 该代码根据应用程序配置或当前环境, 对特定具体工厂类进行初始化。 然后将该工厂对象传递给所有需要创建产品的类。
// 入口 public class Application { private Circle circle; private Square square; private Triangle triangle; public Application(ColorFactory factory) { circle = factory.getCircle(); square = factory.getSquare(); triangle = factory.getTriangle(); } public void show() { circle.getCircleShapeName(); square.getSquareShapeName(); triangle.getTriangleShapeName(); } } // 程序配置 public class Demo { private static Application configureApplication(String color) { Application app; ColorFactory factory; if (color == "red")) { factory = new RedFactory(); } else if(color == "green") { factory = new GreenFactory(); } else if(color == "blue") { factory = new BlueFactory(); } app = new Application(factory); return app; } public static void main(String[] args) { String color = req.getColor(); // 从某处获得的需求 Application app = configureApplication(color); app.show(); } }
-
(移植)找出代码中所有对产品构造函数的直接调用, 将其替换为对工厂对象中相应构建方法的调用。
使用注意
- 明确自己的接口个数和要实现的方法。
- 最外层获得的是根据要求所生成的具体类,所以在声明时使用共同的基类或者接口确保包括所有的变体情况。
- 在具体的变种类中实现具体的功能,在工厂类中只负责按要求装配相应的变种类不进行业务代码编写,在应用层从工厂中获取到实体后再进行业务逻辑代码编写。
工厂模式 Factory Method
工厂方法模式是一种创建型设计模式, 其在父类中提供一个创建对象的方法, 允许子类决定实例化对象的类型。
适用场景
- 在无法确定用户需要的确切对象时,提供一个统一接口根据条件返回不同对象。由于工厂方法将创建产品的代码与实际使用产品的代码分离, 从而能在不影响其他代码的情况下开发新的子类来扩展产品。
实现流程
- 让所有产品都遵循同一接口。 该接口必须声明对所有产品都有意义的方法。
- 在创建类中添加一个空的工厂方法。 该方法的返回类型必须遵循通用的产品接口。
- 在创建者代码中找到对于产品构造函数的所有引用。 将它们依次替换为对于工厂方法的调用, 同时将创建产品的代码移入工厂方法。你可能需要在工厂方法中添加临时参数来控制返回的产品类型。比如使用
switch
分支运算符, 用于选择各种需要实例化的产品类。 - 现在, 为工厂方法中的每种产品编写一个创建者子类, 然后在子类中重写工厂方法, 并将基本方法中的相关创建代码移动到工厂方法中。
通俗解释
抽象工厂的列一维模式,只需要一个工厂根据需要获取同一个接口下的不同风格类