上一篇《Java设计模式之单例模式》详细介绍了单例模式,介绍了单例模式的使用场景,优缺点,同时也写了两种常见的单例模式写法,懒汉式单例模式和饿汉氏单例模式,固然,单例模式的写法还有不少,好比,枚举单例模式,静态内部类单例模式等。有兴趣的能够自行查找资料。本篇开始介绍单例模式的第二篇,工厂方法模式,以及工厂模式的升级版,抽象工厂模式。java
定义:Define an interface for creating an object,but let subclasses decide which class to instantiation.Factory Mehod lets a class defer instantiation to subclasses.翻译过来就是,定义一个用于建立对象的接口,让其子类决定实例化哪一个类。工厂方法让一个类的实例化延迟到其子类。设计模式
上面的定义说明好像很绕口,若是不理解不要紧,咱们用个例子来讲明这个定义:ide
//定义产品接口 public interface Iproduct { public void doSomething(); } //产品实现类 public class ProductA implements Iproduct { @Override public void doSomething() { System.out.println("我是产品A,我能够搞事情"); } } //定义工厂类接口 public interface IFactory { //建立产品工厂方法 < T extends Iproduct> T creatProduct(Class<T> clz); } //工厂方法实现类 public class ProductFactory implements IFactory { @Override public <T extends Iproduct> T creatProduct(Class<T> clz) { Iproduct product=null; try { product= clz.newInstance(); } catch (InstantiationException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } return (T) product; } } //场景类 public class Client { public static void main(String[] args) { IFactory factory=new ProductFactory(); Iproduct product= factory.creatProduct(ProductA.class); product.doSomething(); } }
上述例子,实现了一个简单的工厂方法模式,定义了一个工厂接口类,而后具体的工厂方法实现了建立对象的逻辑。看到这里,有人确定会问,这里要new一个工厂类的实例,和我new一个具体的对象有什么区别呢?反正都要本身new,干吗要搞一个工厂类这么绕呢?对,没错。这里是要new一个工厂类,可是上面的例子建立产品的对象是比较简单,因此感受不出来,若是ProductA的实例建立是一个很是复杂的过程,那么这个时候我经过工厂方法模式建立对象的实例就很方便了。post
确定还有人问,我以为上面这个方式还有点啰嗦,有没有更简便的方式实现工厂模式呢?答案是,有。咱们接下来看看简单工厂模式。简单工厂方法模式就是上述工厂方法模式的简单版本。咱们只要把上述工厂类的接口去掉,而后把工厂实现类改成静态类就能够实现简单工厂方法模式了。代码是这样的:.net
//这里只去掉了接口,改成静态方法 public class ProductFactory { public static <T extends Iproduct> T creatProduct(Class<T> clz) { Iproduct product=null; try { product= clz.newInstance(); } catch (InstantiationException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } return (T) product; } } public class Client { public static void main(String[] args) { Iproduct product= ProductFactory.creatProduct(ProductA.class); product.doSomething(); } }
这里就不用本身去new 工厂类啦,代码也简洁了不少。可是去掉了接口也就意味着后面的扩展是不友好的,因此违反了开闭原则。翻译
定义:Provide an interface for creating families of related or dependent objects without specifying their concrete classes.翻译: 提供一个建立相关或者相互依赖的对象的接口,而且无需指定他们的具体实现类。设计
这里理解可能有点困难,为了便于理解,咱们先引入两个概念。3d
产品等级结构: 产品等级结构即产品的继承结构,如一个抽象类是汽车,其子类就是各个品牌的汽车,好比奔驰,宝马汽车。汽车和奔驰就构成了一个产品等级结构,抽象汽车是父类,而具体品牌的汽车是其子类。code
产品族 : 在抽象工厂模式中,产品族是指由同一个工厂生产的,位于不一样产品等级结构中的一组产品,如奔驰工厂生产的奔驰跑车,宝马公司生产的跑车,奔驰跑车位于奔驰产品等级结构中,宝马跑车位于宝马产品等级结构中。对象
因此,汽车和品牌是一个产品等级结构,而每一个品牌下面有多个产品线,也就是说奔驰牌下面的汽车有多个产品族,好比跑车族,SUV族。奔驰跑车和宝马跑车是一个产品族,奔驰SUV和宝马SUV是一个产品族。因此上面定义中“相关或者相互依赖的对象”就是场景中包含,同一个等级结构中有不一样的产品族。 ,咱们来用一个实际场景来讲明下。
假设,我须要一个汽车工厂,汽车能够生产跑车和SUV车型,那么这个时候用以前的工厂方法模式就不知足了,方法工厂模式只能知足生产一个产品,如今须要生产两个产品。因此咱们在方法工厂模式的基础上改造下来知足这个场景。
//汽车接口 public interface ICar { void dirver(); } //抽象汽车类 public abstract class AbstractProduct implements ICar{ @Override public void dirver() { System.out.println("我是汽车,我能够开动"); } /*** * 展现不一样车的亮点*/ public abstract void showSpecial(); } //宝马SUV实现类 public class BmwSuv extends AbstractProduct { @Override public void showSpecial() { System.out.println("我是宝马牌SUV,个人特色就是多功能用途"); } } //宝马跑车实现类 public class BmwProductRoadster extends AbstractProduct { @Override public void showSpecial() { System.out.println("我是宝马跑车,个人特色就是跑的快"); } } //奔驰SUV public class BenzSuv extends AbstractProduct { @Override public void showSpecial() { System.out.println("我是奔驰牌SUV,个人特色就是多功能用途"); } } //奔驰跑车 public class BenzProductRoadster extends AbstractProduct { @Override public void showSpecial() { System.out.println("我是奔驰跑车,个人特色就是跑的快"); } } //抽象工厂类 public abstract class AbstractFactory { //建立跑车 public abstract < T extends ICar> T createRoadster(); //建立SUV public abstract < T extends ICar> T createSuv(); } //奔驰汽车工厂类 public class BenzFactory extends AbstractFactory { @Override public <T extends ICar> T createRoadster() { return (T) new BenzProductRoadster(); } @Override public <T extends ICar> T createSuv() { return (T) new BenzSuv(); } } //宝马汽车工厂类 public class BmwFactory extends AbstractFactory { @Override public <T extends ICar> T createRoadster() { return (T) new BmwProductRoadster(); } @Override public <T extends ICar> T createSuv() { return (T) new BmwSuv(); } } //场景类 public class Client { public static void main(String[] args) { AbstractFactory bmwFactory=new BmwFactory(); AbstractFactory benzFactory=new BenzFactory(); AbstractProduct bmwRoadster= bmwFactory.createRoadster(); AbstractProduct bmwSuv=bmwFactory.createSuv(); AbstractProduct benzRoadster=benzFactory.createRoadster(); AbstractProduct benzSuv=benzFactory.createSuv(); bmwRoadster.showSpecial(); bmwSuv.showSpecial(); benzRoadster.showSpecial(); benzSuv.showSpecial(); } }
细心的读者应该发现,咱们的改造相对于工厂方法模式而言,只是抽象工厂模式新增了多一个建立方法。这也是抽象工厂模式和工厂方法模式最明显的区别,抽象工厂模式能够知足多类型,多业务的场景,好比汽车工厂能够生产多种类型汽车,就适用于抽象工厂模式。而普通工厂方法模式就是针对生产某一种对象而言比较适用。总结来讲就是,抽象工厂模式适用于多产品族的状况,普通工厂方法模式适用于单产品族状况。
上面介绍了工厂方法模式与抽象工厂模式的定义与实践,同时也衍生了一个简单工厂模式。咱们先来总结下工厂模式的优势与缺点。
优势:
1.良好的封装性,代码结构清晰,不用关注具体对象的建立过程,符合迪米特法则。
2.良好的扩展性,咱们扩展了产品,只要新建对应的工厂类,实现本身的实现逻辑便可。
缺点:
1.对于抽象工厂模式,产品族的扩展比较困难,须要修改顶部抽象工厂类,这会致使全部实现类都要修改,不符合开闭原则。
2.对于简单工厂模式,因为没有接口和抽象父类的约束,从而也会致使扩展只能修改代码,不符合开闭原则。
最后咱们列一个表格来总结下工厂方法模式,简单工厂模式,抽象工厂模式的区别。
简单工厂模式 | 工厂方法模式 | 抽象工厂模式 | |
---|---|---|---|
有无接口或抽象类 | 无 | 有 | 有 |
适用场景 | 通常不涉及扩展,单产品族 | 涉及单产品族,便于扩展 | 多产品族场景,能够扩展等级结构,不便于扩展产品族 |
实现复杂度 | 最简单 | 简单 | 通常 |
《设计模式之禅》