工厂模式的用意是定义一个创建产品对象的工厂接口,将实际创建性工作推迟到子类中。工厂模式可分为简单工厂、工厂方法和抽象工厂模式。注意,我们常说的23种经典设计模式,包含了工程方法模式和抽象工厂模式,而并未包含简单工厂模式。另外,我们平时说的工厂模式,一般默认是指工厂方法模式。
简单工厂
简单工厂模式其实并不算是一种设计模式,更多的时候是一种编程习惯。简单工厂的实现思路是,定义一个工厂类,根据传入的参数不同返回不同的实例,被创建的实例具有共同的父类或接口。简单工厂的适用场景是:
-
需要创建的对象较少。
-
客户端不关心对象的创建过程。
示例:
创建一个可以绘制不同形状的绘图工具,可以绘制圆形,正方形,三角形,每个图形都会有一个draw()方法用于绘图,不看代码先考虑一下如何通过该模式设计完成此功能。
由题可知圆形,正方形,三角形都属于一种图形,并且都具有draw方法,所以首先可以定义一个接口或者抽象类,作为这三个图像的公共父类,并在其中声明一个公共的draw方法:
public interface Shape { void draw(); }
下面就是编写具体的图形,每种图形都实现Shape接口:
// 圆形 class CircleShape implements Shape { public CircleShape() { System.out.println("CircleShape: created"); } @Override public void draw() { System.out.println("draw: CircleShape"); } } // 正方形 class RectShape implements Shape { public RectShape() { System.out.println("RectShape: created"); } @Override public void draw() { System.out.println("draw: RectShape"); } } // 三角形 public class TriangleShape implements Shape { public TriangleShape() { System.out.println("TriangleShape: created"); } @Override public void draw() { System.out.println("draw: TriangleShape"); } }
下面是工厂类的具体实现:
class ShapeFactory { public static Shape getShape(String type) { Shape shape = null; if (type.equalsIgnoreCase("circle")) { shape = new CircleShape(); } else if (type.equalsIgnoreCase("rect")) { shape = new RectShape(); } else if (type.equalsIgnoreCase("triangle")) { shape = new TriangleShape(); } return shape; } }
为工厂类传入不同的type可以new不同的形状,返回结果为Shape 类型,这个就是简单工厂核心的地方了。
工厂方法
工厂方法模式是简单工厂的仅一步深化, 在工厂方法模式中,我们不再提供一个统一的工厂类来创建所有的对象,而是针对不同的对象提供不同的工厂。也就是说每个对象都有一个与之对应的工厂。
工厂方法的实现思路是,定义一个用于创建对象的接口,让子类决定将哪一个类实例化。工厂方法模式让一个类的实例化延迟到其子类。
示例:
现在需要设计一个这样的图片加载类,它具有多个图片加载器,用来加载jpg,png,gif格式的图片,每个加载器都有一个read()方法,用于读取图片。下面我们完成这个图片加载类。
首先完成图片加载器的设计,编写一个加载器的公共接口:
public interface Reader { void read(); }
然后完成各个图片加载器的代码:
// jpg图片加载器 class JpgReader implements Reader { @Override public void read() { System.out.print("read jpg"); } } // png图片加载器 class PngReader implements Reader { @Override public void read() { System.out.print("read png"); } } // gif图片加载器 class GifReader implements Reader { @Override public void read() { System.out.print("read gif"); } }
现在我们按照定义所说定义一个抽象的工厂接口ReaderFactory:
interface ReaderFactory { Reader getReader(); }
里面有一个getReader()方法返回我们的Reader 类,接下来我们把上面定义好的每个图片加载器都提供一个工厂类,这些工厂类实现了ReaderFactory 。
// jpg加载器工厂 class JpgReaderFactory implements ReaderFactory { @Override public Reader getReader() { return new JpgReader(); } } // png加载器工厂 class PngReaderFactory implements ReaderFactory { @Override public Reader getReader() { return new PngReader(); } } // gif加载器工厂 class GifReaderFactory implements ReaderFactory { @Override public Reader getReader() { return new GifReader(); } }
在每个工厂类中我们都通过重写的getReader()方法返回各自的图片加载器对象。
和简单工厂对比一下,最根本的区别在于,简单工厂只有一个统一的工厂类,而工厂方法是针对每个要创建的对象都会提供一个工厂类,这些工厂类都实现了一个工厂基类。
下面总结一下工厂方法的适用场景:
-
客户端不需要知道它所创建的对象的类。
-
客户端可以通过子类来指定创建对应的对象。
抽象工厂
这个模式最不好理解,而且在实际应用中局限性也蛮大的,因为这个模式并不符合开闭原则。实际开发还需要做好权衡。抽象工厂模式是工厂方法的仅一步深化,在这个模式中的工厂类不单单可以创建一个对象,而是可以创建一组对象。这是和工厂方法最大的不同点。
抽象工厂的实现思路是,提供一个创建一系列相关或相互依赖对象的接口,而无须指定它们具体的类。抽象工厂和工厂方法一样可以划分为4大部分:
-
AbstractFactory(抽象工厂):声明了一组用于创建对象的方法,注意是一组。
-
ConcreteFactory(具体工厂):它实现了在抽象工厂中声明的创建对象的方法,生成一组具体对象。
-
AbstractProduct(抽象产品):它为每种对象声明接口,在其中声明了对象所具有的业务方法。
-
ConcreteProduct(具体产品):它定义具体工厂生产的具体对象。
示例:
现在需要做一款跨平台的游戏,需要兼容Android,Ios,Wp三个移动操作系统,该游戏针对每个系统都设计了一套操作控制器(OperationController)和界面控制器(UIController),下面通过抽闲工厂方式完成这款游戏的架构设计。
由题可知,游戏里边的各个平台的UIController和OperationController应该是我们最终生产的具体产品。所以新建两个抽象产品接口。
抽象操作控制器:
interface OperationController { void control(); }
抽象界面控制器:
interface UIController { void display(); }
然后完成各个系统平台的具体操作控制器和界面控制器。
Android:
class AndroidOperationController implements OperationController { @Override public void control() { System.out.println("AndroidOperationController"); } } class AndroidUIController implements UIController { @Override public void display() { System.out.println("AndroidInterfaceController"); } }
IOS:
class IosOperationController implements OperationController { @Override public void control() { System.out.println("IosOperationController"); } } class IosUIController implements UIController { @Override public void display() { System.out.println("IosInterfaceController"); } }
WP:
class WpOperationController implements OperationController { @Override public void control() { System.out.println("WpOperationController"); } } class WpUIController implements UIController { @Override public void display() { System.out.println("WpInterfaceController"); } }
下面定义一个抽闲工厂,该工厂需要可以创建OperationController和UIController。
public interface SystemFactory { public OperationController createOperationController(); public UIController createInterfaceController(); }
在各平台具体的工厂类中完成操作控制器和界面控制器的创建过程。
Android:
public class AndroidFactory implements SystemFactory { @Override public OperationController createOperationController() { return new AndroidOperationController(); } @Override public UIController createInterfaceController() { return new AndroidUIController(); } }
IOS:
public class IosFactory implements SystemFactory { @Override public OperationController createOperationController() { return new IosOperationController(); } @Override public UIController createInterfaceController() { return new IosUIController(); } }
WP:
public class WpFactory implements SystemFactory { @Override public OperationController createOperationController() { return new WpOperationController(); } @Override public UIController createInterfaceController() { return new WpUIController(); } }
下面总结一下抽象工厂的适用场景:
-
和工厂方法一样客户端不需要知道它所创建的对象的类。
-
需要一组对象共同完成某种功能时。并且可能存在多组对象完成不同功能的情况。
-
系统结构稳定,不会频繁的增加对象。
注意:本文归作者所有,未经作者允许,不得转载