Java常用设计模式————工厂模式

简介:

工厂模式(Factory Pattern)是Java中最常用的设计模式之一,又称多态工厂模式、虚拟构造器模式。属于创建型模式。

在工厂模式中,我们在创建对象时不会对客户端暴露创建逻辑,并且是通过使用一个共同的接口来指向新创建的对象。

主要作用:

将类的实例化(具体产品的创建)延迟到工厂类的子类(具体工厂)中完成,即由子类来决定应该实例化那一个类。

应用场景:

1.在编码时无法预见创建哪种类的实例。

2.系统不应依赖于产品类实例如何被创建、组合和表达的细节。

解决问题:

在简单工厂模式中,存在着一个重要的缺陷:工厂一旦需要生产新产品就需要修改工厂类的方法逻辑,违背了OCP原则(Open Closed Principle)。因此为了解决这一问题,工厂方法模式把具体产品的创建推迟到工厂类的子类(具体工厂)中,此时工厂类不再负责所有产品的创建,而只是给出具体工厂必须实现的接口,这样工厂方法模式在添加新产品的时候就不修改工厂类逻辑而是添加新的工厂子类,符合开闭原则,克服了简单工厂模式中的缺点。

实现步骤:

第一步:创建产品接口

package design.pattern.factory1;
/*** 抽象的产品类别* <br>类名:Car<br>* 作者: mht<br>* 日期: 2018年3月20日-下午11:41:50<br>*/
public interface Car {/** 跑*/public void run();/** 漂移*/public void dift();}

第二步:根据业务需要创建具体产品类:产品A产品B实现产品接口

package design.pattern.factory1;/*** 卡车类:实现车接口的具体车类* <br>类名:Truck<br>* 作者: mht<br>* 日期: 2018年3月20日-下午11:45:03<br>*/
public class Truck implements Car{@Overridepublic void run() {System.out.println("卡车跑...");}@Overridepublic void dift() {System.out.println("卡车漂移...不作不死...");}}
package design.pattern.factory1;/*** 公交车:实现车类的具体车类* <br>类名:Bus<br>* 作者: mht<br>* 日期: 2018年3月21日-上午8:24:19<br>*/
public class Bus implements Car{@Overridepublic void run() {System.out.println("公交车跑...");}@Overridepublic void dift() {System.out.println("公交车漂移...不作不死!");}}
package design.pattern.factory1;/*** 轿车:实现骑车类的具体车类* <br>类名:Sedan<br>* 作者: mht<br>* 日期: 2018年3月21日-上午8:24:55<br>*/
public class Sedan implements Car{@Overridepublic void run() {System.out.println("轿车跑...");}@Overridepublic void dift() {System.out.println("轿车漂移...更轻松...");}}

第三步:创建工厂类

这里注意,有些人会单独创建一个工厂接口,然后再创建具体的工厂实现类,每个具体工厂都会有一个用于返回具体产品的方法,在命名上也与具体产品类保持一致,比如:工厂A(实现工厂接口)——(生产)产品A;工厂B——产品B  ……这种方法本人觉得实现起来过于别扭,而工厂类属于中间类,大可不必与产品各个配套,这样反而使得在产生新产品的同时使项目中类的数量成对增加。以下是工厂类的另一种比较方便的实现方式:

package design.pattern.factory1;public class CarFactory {/*** 获得汽车方法 <br>* 作者: mht<br>* 时间:2018年3月20日-下午11:52:54<br>*/public static Car getCar(Class c) {if (c == null)return null;try {/*** 通过newInstance()方法,可以避免工厂类的抽象,将生产过程通过产品的类信息而<br>* 使工厂类达到"一般化"的效果。单独抽象工厂类,然后在生产产品的时候用new的原始方式,<br>* 需要额外扩展对应具体产品的工厂类,而这种newInstance()方式,实际上简化了这种复杂性,<br>* 却同样解决了新增产品需要修改工厂类逻辑的问题。*/Car car = (Car) c.newInstance();return car;} catch (Exception e) {e.printStackTrace();}return null;}
}

以上三步已经达到了工厂方法模式的实现,我们通过一个main方法简单的测试来看一下效果:

package design.pattern.factory1;public class testFactoryPattern {public static void main(String[] args) {Car bus = CarFactory.getCar(Bus.class);bus.run();bus.dift();Car truck = CarFactory.getCar(Truck.class);truck.run();truck.dift();Car sedan = CarFactory.getCar(Sedan.class);sedan.run();sedan.dift();}
}

运行结果:

公交车跑...
公交车漂移...不作不死!
卡车跑...
卡车漂移...不作不死...
轿车跑...
轿车漂移...更轻松...

对工厂模式的理解:

工厂模式充分利用了Java语言中继承和多态的特性。通过分析产品A与产品B或产品C之间存在的共性,抽象出一个可以涵盖这些产品特性的适当超类,然后通过这个超类的具体子类决定具体生产哪种产品而达到多态的目的。多态的意义就是“一个接口,多种实现”,而这里的“接口”不仅仅是表示Interface关键字修饰的抽象类,应该是更广义上的接口或抽象类,上面的代码实际上也可以通过将Car设计成abstract class 通过extends的方式来达到目的。

而更广义上的“工厂模式”实际上是包括了简单工厂、工厂方法、抽象工厂三种从简单到复杂的设计模式。

在有名的OOD的设计原则中有一个叫做里氏代换原则(Liskov Substitution Principle, LSP)。它的实质也就是讲向上转型。它的内容是:任何接收父类型的地方,都应当能够接收子类型,换句话说如果使用的是一个基类的话,那么一定适用于其子类,而且程序察觉不出基类对象和子类对象的区别。LSP是继承复用的基石,只有当派生类可以替换掉基类,软件的功能不受到影响时,基类才能真正被复用。 

 

Published by

风君子

独自遨游何稽首 揭天掀地慰生平