工厂模式的目的:工厂模式主要是为创建对象提供过度接口,以便将创建对象的具体过程屏蔽隔离起来,达到提高灵活性的目的。
工厂模式在《Java与模式》中的分类:
1、简单工厂模式(Simple Factory)
2、工厂方法模式(Factory Method)
3、抽象工厂模式(Abstract Factory)
简单工厂模式:
先来看一个简单的实例吧
Car接口
package com.factory;
public interface Car {
public void run();
public void stop();
}
Benz类(实现Car接口)
package com.factory;
public class Benz implements Car {
@Override
public void run() {
System.out.println("Benz已启动");
}
@Override
public void stop() {
System.out.println("Benz已停止");
}
}
Bmw类(实现Car接口)
package com.factory;
public class Bmw implements Car {
@Override
public void run() {
System.out.println("Bmw已启动");
}
@Override
public void stop() {
System.out.println("Bmw已停止");
}
}
Ford类(实现Car接口)
package com.factory;
public class Ford implements Car {
@Override
public void run() {
System.out.println("Ford已启动");
}
@Override
public void stop() {
System.out.println("Ford已停止");
}
}
下面是CarFactory,Car的工厂类,创建Car的实例
package com.factory;
public class CarFactory {
public static Car getCarInstance(String type) {
Car car = null;
if ("Benz".equals(type)) {
car = new Benz();
}
else if ("Bmw".equals(type)) {
car = new Bmw();
}
else if ("Ford".equals(type)) {
car = new Ford();
}
return car;
}
}
CarTest测试类
package com.factory;
public class CarTest {
public static void main(String args[]) {
// 通过工厂模式获取想要的对象
Car car = CarFactory.getCarInstance("Bmw");
if (car != null) {
car.run();
car.stop();
}
else {
System.out.println("还不能造出该型号的车!");
}
}
}
通过以上实例我们可以很明显的观察到:当我们需要一个car时,不需要自己去创建一个car,而是将创建的任务交给了CarFactory,自己只管使用car就好了。这样对使用者来说就能忽略创建car的细节,仅仅关注自己的业务就可以了;还有就是当创建car的地方很多时,如果出了问题要修改那将是一件很麻烦的事,不过现在只需要修改CarFactory创建满足条件的car即可。
工厂方法模式
上面的“简单工厂模式”很好的满足了客户的需求,即客户只需向工厂(CarFactory)下达指令就可以获取到需要的产品(car),这样客户端(CarTest)免除了直接创建产品对象的责任,而仅仅负责“消费”产品。但是对于工厂(CarFactory)部分确没有那么好运,因为每添加一辆车时都需要去修改工厂类的业务逻辑或判断逻辑使之能生产相应的产品,这样显然违背了程序的“开闭原则”(对扩展开放,对修改关闭),那有没有什么办法解决这个问题呢?答案当然是肯定的,就是下面要介绍的“工厂方法模式”。
“工厂方法模式”去掉了“简单工厂模式”中的静态方法(CarFactory中的getCarInstance()方法),使得它可以被子类继承。这样在“简单工厂模式”里集中在工厂方法上的压力就可以由“工厂方法模式”里不同的工厂子类来分单。
说了这么多还是先上一段例子吧,通过实例来了解什么是“工厂方法模式”及其用法
Car接口
package com.factory;
public interface Car {
public void run();
public void stop();
}
Benz类
package com.factory;
public class Benz implements Car {
@Override
public void run() {
System.out.println("Benz已启动");
}
@Override
public void stop() {
System.out.println("Benz已停止");
}
}
Bmw类
package com.factory;
public class Bmw implements Car {
@Override
public void run() {
System.out.println("Bmw已启动");
}
@Override
public void stop() {
System.out.println("Bmw已停止");
}
}
Ford类
package com.factory;
public class Ford implements Car {
@Override
public void run() {
System.out.println("Ford已启动");
}
@Override
public void stop() {
System.out.println("Ford已停止");
}
}
Driver接口
package com.factory;
public interface Driver {
public Car driverCar();
}
BenzDriver类
package com.factory;
public class BenzDriver implements Driver {
@Override
public Car driverCar() {
return new Benz();
}
}
BmwDriver类
package com.factory;
public class BmwDriver implements Driver {
@Override
public Car driverCar() {
return new Bmw();
}
}
FordDriver类
package com.factory;
public class FordDriver implements Driver {
@Override
public Car driverCar() {
return new Ford();
}
}
CarTest测试类
package com.factory;
public class CarTest {
public static void main(String args[]) {
// 通过工厂模式获取想要的对象
Driver driver = new BenzDriver();
Car car = driver.driverCar();
car.run();
car.stop();
}
}
工厂方法模式可以通过子类来分摊简单工厂里工厂类的压力,但是工厂方法模式使得对象的数量成倍的增长,当产品的种类非常多时会出现大量与之对应的工厂对象。就工厂方法模式和简单工厂模式来讲应该是各有利弊,下面通过两者的比较能更清楚的说明问题。
简单工厂模式是把核心放在一个实体类上(CarFactory),而工厂方法模式的核心是一个抽象工厂(Driver)。工厂方法模式可以允许很多实体的工厂类从抽象工厂类继承下来,从而可以在实际上成为多个简单工厂模式的综合,从而推广了简单工厂模式(例如:我们可以把BenzDriver类看着是简单工厂模式里的实体类(CarFactory),这样例子中的工厂方法模式就可以看着是由三个简单工厂模式构成的)。反过来我们也可以由工厂方法模式推到简单工厂模式,当工厂方法模式中只有一个实体类,再去掉格式上的接口后,也就演变成了简单工厂模式。所以也有人(GOF《设计模式》)认为简单工厂模式是工厂方法模式的一种特例,将两者都归结到工厂方法模式中。
使用工厂模式增加了我们的代码量(代码量比较:工厂方法模式 > 简单工厂模式 > 直接实现),但是提高了可维护性、可扩展性(可维护性、可扩展性:工厂方法模式 > 简单工厂模式 > 直接实现),所以多写些代码还是值得的。但是工厂模式并没能真正避免代码的改动,例如:简单工厂模式中,当添加一个新的产品时,就需要去实现这个产品类并修改工厂类使之能生产改产品(因为工厂方法模式是由n个简单工厂模式组成,所以也存在这个问题)。
面对这种情况,Java的反射机制与配置文件的巧妙结合很好的突破了这个问题。(这在spring中有完美的体现)
抽象工厂模式
提供了一个创建一系列相关或者相互依赖对象的接口,而无需知道它们具体的类。同上我们还是通过一个例子来理解下抽象工厂模式。
由于这个例子类和接口有点多,我们先看下整个的UML图吧。
下面来看一下具体的每个类的代码吧
ComputerFactory接口
package com.factory;
public interface ComputerFactory {
public Computer getCpu();
public Computer getHardDisk();
public Computer getMainBoard();
}
IbmFactory类
package com.factory;
public class IbmFactory implements ComputerFactory{
@Override
public Computer getCpu() {
return (Computer) new InterCpu();
}
@Override
public Computer getHardDisk() {
return (Computer) new WestDigitHD();
}
@Override
public Computer getMainBoard() {
return (Computer) new MpeMB();
}
}
DellFactory类
package com.factory;
public class DellFactory implements ComputerFactory{
@Override
public Computer getCpu() {
return (Computer) new AmdCpu();
}
@Override
public Computer getHardDisk() {
return (Computer) new MastoxHD();
}
@Override
public Computer getMainBoard() {
return (Computer) new MngMB();
}
}
package com.factory;
public interface Computer {
public Double getPrice();
public String getModel();
}
Cpu抽象类
package com.factory;
public abstract class Cpu implements Computer {
public abstract Double getPrice();
public abstract String getModel();
public void show() {
System.out.println("我是Cpu");
}
}
HardDisk抽象类
package com.factory;
public abstract class HardDisk implements Computer {
public abstract Double getPrice();
public abstract String getModel();
public void show() {
System.out.println("我是HardDisk");
}
}
MainBoard抽象类
package com.factory;
public abstract class MainBoard implements Computer {
public abstract Double getPrice();
public abstract String getModel();
public void show() {
System.out.println("我是MainBoard");
}
}
InterCpu类
package com.factory;
public class InterCpu extends Cpu {
@Override
public Double getPrice() {
return 300D;
}
@Override
public String getModel() {
return "inter i7";
}
}
AmdCpu类
package com.factory;
public class AmdCpu extends Cpu {
@Override
public Double getPrice() {
return 100D;
}
@Override
public String getModel() {
return "AMD am2";
}
}
WestDigitHD类
package com.factory;
public class WestDigitHD extends HardDisk {
@Override
public Double getPrice() {
return 330D;
}
@Override
public String getModel() {
return "WestDigit HD 1";
}
}
MastoxHD类
package com.factory;
public class MastoxHD extends HardDisk {
@Override
public Double getPrice() {
return 110D;
}
@Override
public String getModel() {
return "Mastox HD 1";
}
}
MpeMB类
package com.factory;
public class MpeMB extends MainBoard {
@Override
public Double getPrice() {
return 360D;
}
@Override
public String getModel() {
return "MpeMB";
}
}
MngMB类
package com.factory;
public class MngMB extends MainBoard {
@Override
public Double getPrice() {
return 120D;
}
@Override
public String getModel() {
return "MngMB";
}
}
package com.factory;
public class Customer {
public static void main(String args[]) {
ComputerFactory cf = new IbmFactory();
Computer c = cf.getCpu();
System.out.println("型号:" + c.getModel() + "; " + " 价格:" + c.getPrice());
Cpu cpu = (Cpu) c;
cpu.show();
}
}
在调用的地方很明显的展现了只要通过相关接口就可以得到对应的产品,而无需指定它们具体的类,由此抽象工厂具有工厂方法模式的一切优点。此外抽象工厂的优点有可以在类的内部对产品簇(在该例中getCpu、getPrice可以看成是一个产品簇,限于篇幅就不展开将了)进行约定,比如在该例中,IbmFactory就只能有InterCpu而不能有与InterCpu同级的AmdCpu。缺点就是当扩展产品簇是一件十分费力的事,比如我想添加一个和getCpu同级的getDisplayer的产品簇,那么IbmFactory、DellFactory、ComputerFactory都需要修改;如果扩展一个和getPrice同级的产品簇那修改的会更多,所以使用抽象工厂模式时,对产品等级结构的划分非常重要。
总结
当需要创建的对象是一系列相互关联或相互依赖的产品族时,便可以使用抽象工厂模式。说的更明白一点,就是一个继承体系中,如果存在着多个等级结构(即存在着多个抽象类),并且分属各个等级结构中的实现类之间存在着一定的关联或者约束,就可以使用抽象工厂模式。假如各个等级结构中的实现类之间不存在关联或约束,则使用多个独立的工厂来对产品进行创建,则更合适一点。
无论是简单工厂模式,工厂方法模式,还是抽象工厂模式,他们都属于工厂模式,在形式和特点上也是极为相似的,他们的最终目的都是为了解耦。在使用时,我们不必去在意这个模式到底工厂方法模式还是抽象工厂模式,因为他们之间的演变常常是令人琢磨不透的。经常你会发现,明明使用的工厂方法模式,当新需求来临,稍加修改,加入了一个新方法后,由于类中的产品构成了不同等级结构中的产品族,它就变成抽象工厂模式了;而对于抽象工厂模式,当减少一个方法使的提供的产品不再构成产品族之后,它就演变成了工厂方法模式。
所以,在使用工厂模式时,只需要关心降低耦合度的目的是否达到了。