以下为工厂模式的详解,包括简单工厂,普通工厂模式,抽象工厂。
引子:
假设有一个交通工具公司,生产自行车,汽车,飞机等,现要销售该公司的产品,要怎么设计呢?
在交通工具商店中加一个if else判断如果是自行车就实例化(new)一个自行车,如果是汽车就实例化(new)一个汽车吗,当然不是,这样的话如果将来又加了多种交通工具那要更改每一个商店的代码,这样的话更改太多,我们应该把这部分可能变更的代码封装到另一个对象中,这个对象只管生产何种交通工具,要获得交通工具就用它。
简单工厂:
类图:
设计:
/** * 抽像的交通工具类,里面有生产交通工具的过程方法(控制生产过程) * @author Homg * */ public abstract class Vehicle { public abstract void produceComponent(); public abstract void assemble(); public abstract void test(); }
具体产品类,其他具体产品类(bike,plane)省略,完整代码在文章的最下方有下载地址:
/** * 具体的产品,继承自抽象类,以用被工厂生产出来 * @author Homg * */ public class Car extends Vehicle{ @Override public void produceComponent() { // TODO Auto-generated method stub System.out.println("生产汽车零件"); } @Override public void assemble() { // TODO Auto-generated method stub System.out.println("组装成汽车"); } @Override public void test() { // TODO Auto-generated method stub System.out.println("测试汽车性能"); } }
/** * 简单交通工具工厂,这是唯一new具体交通工具的地方 * * @author Homg * */ public class SimpleVehicleFactory { // 该方法也可以是静态的(静态工厂) public Vehicle createVehicle(String type) { Vehicle vehicle = null; if ("bike".equals(type)) { vehicle = new Bike(); } else if ("car".equals(type)) { vehicle = new Car(); } else if ("plane".equals(type)) { vehicle = new Plane(); } //可以设置默认产品以免为null return vehicle; } }
/** * 销售交通工具,工厂的使用者。 * * @author Homg * */ public class VehicleStore { // 工厂的引用,从构造函数中获得 private SimpleVehicleFactory factory; public VehicleStore(SimpleVehicleFactory factory) { this.factory = factory; } // 通过传入订单的类型来获得相应的产品,不需要实例化(new)任何一个具体类,全部通过createVehicle()来获得。 public Vehicle orderVehicle(String type) { Vehicle vehicle; vehicle = factory.createVehicle(type); vehicle.produceComponent(); vehicle.assemble(); vehicle.test(); return vehicle; } }
测试:
public static void main(String[] args) { SimpleVehicleFactory factory = new SimpleVehicleFactory(); VehicleStore vehicleStore = new VehicleStore(factory); // 依次生产三种交通工具 Vehicle vehicle1 = vehicleStore.orderVehicle("car"); System.out.println("-------------------------------------"); Vehicle vehicle2 = vehicleStore.orderVehicle("bike"); System.out.println("-------------------------------------"); Vehicle vehicle3 = vehicleStore.orderVehicle("plane"); }
运行结果:
生产汽车零件
组装成汽车
测试汽车性能
-------------------------------------
生产自行车零件
组装成自行车
测试自行车性能
-------------------------------------
生产飞机零件
组装成飞机
测试飞机性能
˙☆`·.·˙˙`·..·˙˙`·..·˙☆`·.·˙˙`·..·˙☆˙˙☆`·.·˙˙`·..·˙˙`·..·˙☆`·.·˙˙`·..·˙☆˙˙☆`·.·˙˙`·..·˙˙`·..·˙☆`·.·˙˙`·..·˙☆˙
以后如果有新的交通工具要生产,只需要更改工厂类一处即可,商店类中不需要实例化任何一个具体的交通工具类,实例化(new)操作都放到工厂类的方法中。工厂类中的创建方法也可以改成静态的(静态工厂),这样可以不用实例化对象来使用工厂方法。
简单工厂严格来说并不是真正的工厂模式,下来我们来看普通工厂模式:
现在该公司不仅要在中国销售产品,还要把产品销售到俄罗斯,也就是说,不仅要分多种产品类型,还要分不同区域生产不同风格的产品。
先看一下工厂模式的基本类图:
设计(省略部分类似代码,完整代码在文章的最下方有下载地址。):
首先要进行一些质量控制,确保分公司产品是用的总公司的流程,但不同地区的产品又需要有自己的变化,所以产品类应该这样:
/** * 产品类,抽像的交通工具类,里面有生产交通工具的过程方法(控制生产过程),但抽象的由子具体实现 * * @author Homg * */ public abstract class Vehicle { String name; //各种零件 String tyre; String engine; String body; public void produceComponent() { System.out.println("名字:" + name); System.out.println("轮胎:" + tyre); System.out.println("引擎:" + engine); System.out.println("机身:" + body); } public abstract void assemble(); public abstract void test(); }
子类决定具体的产品(其他具体产品类省略):
/** * 具体的产品,继承自抽象类,根据不同地域有不同的产品 * @author Homg * */ public class ChineseCar extends Vehicle{ public ChineseCar() { name="中国汽车"; tyre="中国汽车轮胎"; engine="中国汽车引擎"; body="中国风格汽车机身"; } @Override public void assemble() { // TODO Auto-generated method stub System.out.println("组装成中国风格汽车"); } @Override public void test() { // TODO Auto-generated method stub System.out.println("测试俄中国格汽车性能"); } }
/** * 具体的产品,继承自抽象类,根据不同地域有不同的产品 * @author Homg * */ public class RussiaCar extends Vehicle{ public RussiaCar() { name="俄罗斯汽车"; tyre="俄罗斯汽车轮胎"; engine="俄罗斯汽车引擎"; body="俄罗斯风格汽车机身"; } @Override public void assemble() { // TODO Auto-generated method stub System.out.println("组装成俄罗斯风格汽车"); } @Override public void test() { // TODO Auto-generated method stub System.out.println("测试俄罗斯风格汽车性能"); } }
工厂类需要制定一个框架,既要生产产品,不同区域又可以生产不同的产品(抽象的工厂方法):
/** * 创建者类,定义了一个抽象的工厂方法,由子类具体实现创建什么新产品 * @author Homg * */ public abstract class VehicleFactory { //生产产品,不用管具体生产什么产品,由createVehicle方法来管 public Vehicle orderVehicle(String type) { Vehicle vehicle; vehicle = createVehicle(type); vehicle.produceComponent(); vehicle.assemble(); vehicle.test(); return vehicle; } //抽象的创建产品方法,返回具体的产品,参数决定是什么产品。 protected abstract Vehicle createVehicle(String type); //其他方法 }
子类工厂重写工厂方法,决定生产什么地区的产品:
/** * 具体的工厂类,根据不同地域创建不同的产品 * * @author Homg * */ public class ChineseVehicleFactory extends VehicleFactory { // 创建不同的产品 @Override protected Vehicle createVehicle(String type) { // TODO Auto-generated method stub Vehicle vehicle = null; if ("bike".equals(type)) { vehicle = new ChineseBike(); } else if ("car".equals(type)) { vehicle = new ChineseCar(); } // 可以设置默认产品以免为null return vehicle; } }
/** * 具体的工厂类,根据不同地域创建不同的产品 * * @author Homg * */ public class RussiaVehicleFactory extends VehicleFactory { // 创建不同的产品 @Override protected Vehicle createVehicle(String type) { // TODO Auto-generated method stub Vehicle vehicle = null; if ("bike".equals(type)) { vehicle = new RussiaBike(); } else if ("car".equals(type)) { vehicle = new RussiaCar(); } // 可以设置默认产品以免为null return vehicle; } }
测试:
public static void main(String[] args) { VehicleFactory chinesefactory=new ChineseVehicleFactory(); Vehicle chineseVehicle1=chinesefactory.orderVehicle("bike"); System.out.println("--------------------------------------"); Vehicle chineseVehicle2=chinesefactory.orderVehicle("car"); System.out.println("--------------------------------------"); VehicleFactory russiaFactory=new RussiaVehicleFactory(); russiaFactory.orderVehicle("bike"); System.out.println("--------------------------------------"); russiaFactory.orderVehicle("car"); }
运行结果:
名字:中国自行车
轮胎:中国自行车轮胎
引擎:生物动力
机身:中国风格自行车机身
组装成中国风格自行车
测试中国风格自行车性能
--------------------------------------
名字:中国汽车
轮胎:中国汽车轮胎
引擎:中国汽车引擎
机身:中国风格汽车机身
组装成中国风格汽车
测试俄中国格汽车性能
--------------------------------------
名字:俄罗斯自行车
轮胎:俄罗斯自行车轮胎
引擎:生物动力
机身:俄罗斯风格自行车机身
组装成俄罗斯风格自行车
测试俄罗斯风格自行车性能
--------------------------------------
名字:俄罗斯汽车
轮胎:俄罗斯汽车轮胎
引擎:俄罗斯汽车引擎
机身:俄罗斯风格汽车机身
组装成俄罗斯风格汽车
测试俄罗斯风格汽车性能
类图(产品和工厂是平行的类层级):
理解:
工厂方法可以封装实例化的行为,封装以后可能经常变化的代码,避免代码的重复,方便以后维护。
˙☆`·.·˙˙`·..·˙˙`·..·˙☆`·.·˙˙`·..·˙☆˙˙☆`·.·˙˙`·..·˙˙`·..·˙☆`·.·˙˙`·..·˙☆˙˙☆`·.·˙˙`·..·˙˙`·..·˙☆`·.·˙˙`·..·˙☆˙
现在来谈谈零件的生产,每次该公司要生产一批零件,用以制造某个产品,这时可以看看抽象工厂:
基本类图如下:
设计:
抽象工厂类:
/** * 抽象工厂接口,定义了一组接口用来创建产品 * @author Homg * */ public interface ComponentFactory { public Tyre createTyre(); public Engine createEngine(); public Body createBody(); }
具体工厂类,不同地区的零件有不同的具体工厂:
/** * 具体工厂,实现了产品家族,用户想要什么产品就用什么工厂,不需要实例化任何产品 * @author Homg * */ public class ChineseComponentFactory implements ComponentFactory { @Override public Tyre createTyre() { // TODO Auto-generated method stub return new ChineseTyre(); } @Override public Engine createEngine() { // TODO Auto-generated method stub return new ChineseEngine(); } @Override public Body createBody() { // TODO Auto-generated method stub return new ChineseBody(); } }
/** * 具体工厂,实现了产品家族,用户想要什么产品就用什么工厂,不需要实例化任何产品 * @author Homg * */ public class RussiaComponentFactory implements ComponentFactory { @Override public Tyre createTyre() { // TODO Auto-generated method stub return new RussiaTyre(); } @Override public Engine createEngine() { // TODO Auto-generated method stub return new RussiaEngine(); } @Override public Body createBody() { // TODO Auto-generated method stub return new RussiaBody(); } }
零件家族(省略其他零件类:engine,body。完整代码在文章的最下方有下载地址):
/** * 抽象产品 * @author Homg * */ public abstract class Tyre { String name; public String getName() { return name; } }
/** * 具体产品 * @author Homg * */ public class RussiaTyre extends Tyre { public RussiaTyre() { name="俄罗斯轮胎"; } }
/** * 具体产品 * @author Homg * */ public class ChineseTyre extends Tyre { public ChineseTyre() { name = "中国轮胎"; } }
客户类:
/** * 客户类 * @author Homg * */ public class Client { private Tyre tyre; private Engine engine; private Body body; private ComponentFactory componentFactory; public Client(String zoom) { if ("俄罗斯".equals(zoom)) { componentFactory = new RussiaComponentFactory(); tyre = componentFactory.createTyre(); engine = componentFactory.createEngine(); body = componentFactory.createBody(); System.out.println("生产的一批零件为:" + tyre.getName() + "," + engine.getName() + "," + body.getName()); } else if ("中国".equals(zoom)) { componentFactory = new ChineseComponentFactory(); tyre = componentFactory.createTyre(); engine = componentFactory.createEngine(); body = componentFactory.createBody(); System.out.println("生产的一批零件为:" + tyre.getName() + "," + engine.getName() + "," + body.getName()); } } }
测试:
public static void main(String[] args) { Client client1=new Client("俄罗斯"); System.out.println("------------------------------"); Client client2=new Client("中国"); }
运行结果:
生产的一批零件为:俄罗斯轮胎,俄罗斯引擎,俄罗斯机身
------------------------------
生产的一批零件为:中国轮胎,中国引擎,中国机身
理解:
由上面可以看出,抽象工厂是用来创建一组产品的,也就是产品家族,用户不需要关心实际生产的具体产品是什么,只需要使用相应的工厂,这样可以将用户从具体产品中解耦。
而普通工厂可以理解为是用来生产一个产品,抽象工厂用来生产产品家族。
总结:
普通工厂模式:定义了一个创建产品对象的接口,但由子类决定要实例化的类是哪一个。工厂方法让类把实例化推迟到子类。
抽象工厂模式:提供一个接口,用于创建相关或依赖对象的家族,而不需要明确指定具体类。
完整代码下载地址(也可以留下邮箱发给你):