`

工厂设计模式事例及图解

阅读更多

简单工厂模式是类的创建模式,又叫做静态工厂方法(Static Factory Method)模式。简单工厂模式是由一个工厂对象决定创建出那一种产品类的实例。
1. 工厂模式的几种形态
工厂模式专门负责将大量有共同接口的类实例化。工厂模式可以动态决定将哪一个类
实例化,不必事先知道每次要实例化哪一个类。工厂模式有以下几种形态:
(1)简单工厂(Simple Factory)模式,又称静态工厂方法模式(Static Factory Method Pattern)。
(2)工厂方法(Factory Method)模式,又称多态性工厂(Polymorphic Factory)模式或虚拟构造子(Virtual Constructor)模式;
(3)抽象工厂(Abstract Factory)模式,又称工具箱(Kit 或Toolkit)模式。
下面就是简单工厂模式的简略类图。
简单工厂模式,或称静态工厂方法模式,是不同的工厂方法模式的一个特殊实现。在其他文献中,简单工厂往往作为普通工厂模式的一个特例讨论。
在Java语言中,通常的工厂方法模式不能通过设计功能的退化给出静态工厂方法模式。
因为一个方法是不是静态的,对于Java 语言来说是一个很大的区别,必须在一开始的时候就加以考虑。这就是本人将简单工厂单独提出来讨论的一个原因。学习简单工厂模式是对学习工厂方法模式的一个很好的准备,也是对学习其他模式的一个很好的准备。
2. 简单工厂模式的引进
简单工厂模式又叫静态工厂模式,顾名思义,它是用来实例化目标类的静态类。下面我主要通过一个简单的实例说明简单工厂及其优点。
现在我们通过一个例子看一下:
比如说有一个汽车公司,专门向市场销售各牌子的汽车。我们做一个相应的系统(例子):
首先我们把汽车堪称是一个接口注1,在这个接口里面有两个抽象方法—进货及卖(销售汽车)。然后根据需要去实现这个接口。


注1:在面向对象设计方法中有很多值得提倡的方法,这些方法可以为我们的设计带来很大的灵活性,可复用性。其中一个原则就是“针对接口编程,而不是针对实现编程” 。这个原则带来的好处有以下几点:

l       Client不必知道其使用对象的具体所属类。

l       Client无需知道特定类,只需知道他们所期望的接口。

l       一个对象可以很容易地被(实现了相同接口的)的另一个对象所替换。

l       对象间的连接不必硬绑定(hardwire)到一个具体类的对象上,因此增加了灵活性。

在接口完成(interface Car)了、汽车的概念已经出来以后,我们要去实现这个接口(根据我们想要销售的汽车类型,例如奔驰、福特、……等)。

 

这个时候,如果我们要销售奔驰车,就要在main方法(客户端)去实例化一个“class Benz”,并在客户端(main方法)中去实例化相关对象和调用对应的方法。

运行程序,正常。

这个时候如果我们想销售福特了,怎么办?这个时候我必须去修改客户端的程序(main方法),把Car c=new Benz();改成Car c=new Ford();。改动就有可能出错误,就要进行测试,……,这样显然对程序是不利的。我们应当怎样解决这个问题呢?


 
我们就想到,我们可以加一个工厂类,让这个工厂类为客户端实例化一个对象:


 

到目前为止,这个程序就是一个简单的工厂模式,但是这里还存在着一个问题:在我的客户端(main方法的地方),我需要即可以要Benz也可以要Ford,可以动态的去选择它,该怎么办呢?
这个时候我们就在想,我们可以把在class Factory中的getCarInstance()方法进行改进,让该方法可以接收参数,也就是说,客户端想要什么,我的工厂就按照客户端的要求去提供,首先对class Factory中的getCarInstance()进行改进,然后客户端程序也做相应的调整:

 

 


运行正常。但是现在还有问题:在传递参数的时候只能传入Benz或者Ford,如果传入其它参数就会出问题,怎么办呢?应当在客户端这里加一个判断,看Factory.getCarInstance(“Benz”);返回的参数是不是“空”的:


现在又有一个问题,如果我们不仅卖奔驰和福特,我们还卖别的牌子的汽车,也就是说如果我们现在要扩充一个子类,就必须去修改“工厂”(class Factory),在“工厂”中在添加一个if去判断并去实例化相应的子类,例如我们想要销售丰田汽车,就必须修改“工厂”。怎样解决这个问题呢?
我们现在要解决的问题是,扩充子类,怎样不用去修改工厂:如果是用java语言来实现的话,我们自然会想到利用java的反射机制注2 ,
注2:java的反射机制:JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法;这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。Java反射机制主要提供了以下功能: 在运行时判断任意一个对象所属的类;在运行时构造任意一个类的对象;在运行时判断任意一个类所具有的成员变量和方法;在运行时调用任意一个对象的方法;生成动态代理。
用java的反射机制解决这个问题,那么在“工厂”中就不用if判断了,

 

 

这个时候在客户端的Car c=Factory.getCarInstance(“Benz”);中无论是输入Benz还是输入Ford都会等到正确的运行结果。完整的程序如下:

package org.chenb.factorydemo;

 

interface Car{

    public void stock();

    public void sell();

}

 

class Benz implements Car{

    public void stock(){

        System.out.println("Benz进货了………");

    }

    public void sell(){

        System.out.println("Benz卖出了………");

    }

}

class Ford implements Car{

    public void stock(){

        System.out.println("Ford进货了………");

    }

    public void sell(){

        System.out.println("Ford卖出了………");

    }

}

 

class Factory{

    public static Car getCarInstance(String type){

        Car c=null;

        try {

              c=(Car)Class.forName("org.chenb.factorydemo."+type).newInstance();

        } catch (InstantiationException e) {

              // TODO Auto-generated catch block

              e.printStackTrace();

        } catch (IllegalAccessException e) {

              // TODO Auto-generated catch block

              e.printStackTrace();

        } catch (ClassNotFoundException e) {

              // TODO Auto-generated catch block

              e.printStackTrace();

        }

   

        return c;

    }

}

public class FactoryDemo {

 

    public static void main(String[] args) {

        Car c=Factory.getCarInstance("Benz");

        if(c!=null){

              c.stock();

              c.sell();

        }else{

              System.out.println("无此类型的汽车销售……");

        }

       

    }

 

}

 

这个时候,如果我们添加一个子类,比如我们除销售奔驰、福特以外,还要销售丰田、奇瑞,就不需要去修改工厂了,只要去添加一个子类即可,例如我们要销售丰田汽车了,就添加一个子类Toyota去实现汽车接口:

class Toyota implements Car{

    public void stock(){

        System.out.println("Toyota进货了………");

    }

    public void sell(){

        System.out.println("Toyota卖出了………");

    }

}

在客户端的Car c=Factory.getCarInstance(“Toyota”);中输入Toyota即可。
其实这也实现了面对对象设计的一个很重要的原则—开闭原则(OCP),即一个软件实体应当对扩展开放,对修改关闭。

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics