码迷,mamicode.com
首页 > 其他好文 > 详细

工厂模式

时间:2015-07-09 06:12:11      阅读:171      评论:0      收藏:0      [点我收藏+]

标签:

先说一下设计模式的共同特点,就是将简单的问题复杂化,明明可以用简单的几行代码的搞定的事情偏偏要给代码穿上各种衣服,带上各种帽子,使得代码的运行不再高效。但是这种看似“臃肿”的代码却给我们以后的维护与修改带来了极大的便利,而且计算机硬件性能的提升允许我们在效率上有所任性,同时这也是软件开发的一种趋势,就是工程型越来越强,维护的比重在软件的整体周期中也会越来越大!所以在开发软件的过程中有效的使用各种设计模式可以极大的提高代码的健壮性!

工厂模式

(1)     简单工厂模式

 

实例:我们要采摘水果(苹果、桃子)

 

简单定义苹果(Apple.java)与香蕉(Banana.java)两个类

 

Apple.java:

 

package asimplefactory01;

 

public class Apple{

    /*

     * 采集

     */

    public void get(){

       System.out.println("采集苹果");

    }

}

 

Banana.java:

 

package asimplefactory01;

 

public class Banana{

    /*

     * 采集

     */

    public void get(){

       System.out.println("采集香蕉");

    }

}

 

我们分别在Apple.java与Banana.java两个类中定义了get方法,如果我们要想摘取苹果与香蕉,那么我们可以写一个main函数,直接调用

 

package asimplefactory01;

 

public class TMainClass {

 

    public static void main(String[] args) {

       Apple apple = new Apple();

       Banana banana = new Banana();

      

       apple.get();

       banana.get();

    }

}

 

运行结果如下:

采集苹果

采集香蕉

 

一切看似妥妥的没问题,没错运行真的没有问题,但是如果我们此时不想要苹果与香蕉了,而是想摘梨子,我们该怎么办呢?同学会说,那我们在创建一个梨子好了,OK,那我们先创建一个梨子的类

Pear.java

 

package afactorymethod01;

 

public class Pear{

 

    @Override

    public void get() {

       System.out.println("采集梨子");

    }

 

}

 

此时,我们需要修改main函数中的代码为

package asimplefactory01;

 

public class TMainClass {

 

    public static void main(String[] args) {

       Pear pear = new Pear();

      

       pear.get();

    }

}

到目前为止,好像看起来一切都很和谐,因为我们的需求都能得到很好的实现,但是如果此时,客户对我们说,我们不要梨子了,我们想要荔枝,我们想要桃子,这个时候我们该怎么办呢?是不是开始头大了?因为我们不仅要不断地添加新的类,更恶心人的是我们还要不停的修改main函数中的代码,尤其是当main函数中已经有成千上万行代码的时候(这里只是严重夸张一下),万一我们一不小心手贱,多改了一行呢?

 

 

 

好了,下面进入我们的简单工厂模式:

 

来个定义先:

简单工厂模式属于类的创建型模式,又叫做静态工厂方法模式。通过专门定义一个类来负责创建其他类的实例,被创建的实例通常都具有共同的父类。

 

首先简单工厂模式分为3种角色

 

(1)  工厂角色:

该角色是简单工厂模式的核心,它负责实现创建所有实例的内部逻辑。工厂类可以被外界直接调用,创建所需要的产品对象。

 

(2)  抽象角色:

简单工厂模式所创建的所有对象的父类,它负责描述所有实例所有公用的接口。

 

(3)  具体产品角色:

简单工厂模式所创建的具体的实例对象。

 

话不多少,接着贴代码,看看使用简单的工厂模式如何解决 上面所出现的问题。

首先根据定义,先抽象苹果、香蕉、梨子等水果的一个父类Fruit.java,在这里有的同学可能会问,为什么要为Apple,Banana等创建父类呢?原因很简单,因为我们通过“工厂”返回的具体产品是根据用户需求而改变的,即事先我们并不知道要返回的是Apple还是Banana,所以我们必须要为他们具体的类构建一个父类,这样的话再返回的时候就可以统一返回Fruit了。

 

package asimplefactory01;

 

public interface Fruit {

    /*

     * 采集

     */

    public void get();

}

 

然后创建具体产品角色:让所有的水果都继承Fruit.java

 

继承了Fruit的苹果Apple.java:

package asimplefactory01;

 

public class Apple implements Fruit{

    /*

     * 采集

     */

    public void get(){

       System.out.println("采集苹果");

    }

}

 

继承了Fruit的苹果Banana.java:

package asimplefactory01;

 

public class Banana implements Fruit{

    /*

     * 采集

     */

    public void get(){

       System.out.println("采集香蕉");

    }

}

 

最后我们创建出一个能够采摘所有水果的大工厂:FruitFactory.java

 

package asimplefactory02;

 

public class FruitFactory {

    /*

     * get方法,获得所有产品对象

     */

    public static Fruit getFruit(String type) throws InstantiationException, IllegalAccessException, ClassNotFoundException          {

       if(type.equalsIgnoreCase("apple")) {

           return Apple.class.newInstance();

          

       } else if(type.equalsIgnoreCase("banana")) {

           return Banana.class.newInstance();

       } else {

           System.out.println("找不到相应的实例化类");

           return null;

       }

    }

}

 

在FruitFactory这个类中,我们编写了public static Fruit getFruit(String type)方法,该方法通过传递String类型的参数就可以返回出相应的水果,是不是要比没有使用简单工厂模式的实现要方便多了?

 

下面我们来给各位送点水果,看看效果怎么样:

 

package asimplefactory02;

 

public class MainClass {

    public static void main(String[] args) throws InstantiationException, IllegalAccessException, ClassNotFoundException {

    //这种是最常见的使用方式,而且这种方式的用户体验也是最好的,适用性是最好的

       Fruit apple = FruitFactory.getFruit("apple");

       Fruit banana = FruitFactory.getFruit("Banana");

       apple.get();

       banana.get();

    }

}

 

运行结果:

采集苹果

采集香蕉

 

OK,上面所描述的就是简单工厂模式,简单工厂模式很好地解决了main函数的简化问题,用户在使用时可以直接根据工厂类去创建所需的实例,而无需了解这些对象是如何创建以及如何组织的。有利于整个软件体系结构的优化。但是有的同学可能已经发现了,如果此时想添加新的水果的话,那FruitFactory.java中岂不是得像main.java那样添加代码,因为每新添加一种水果,就得在FruitFactory.java getFruit方法中添加一种新的else if语句。没错,简单工厂模式的缺点也正体现在其工厂类上,由于工厂类集中了所有实例的创建逻辑,所以“高内聚”方面做的并不好。另外,当系统中的具体产品类不断增多时,可能会出现要求工厂类也要做相应的修改,扩展性并不很好。

 

所以为了解决上述问题,工厂模式正式出现在我们的面前了

 

(2)     工厂模式

工厂模式与简单工厂模式最大的区别就是工厂模式为每一个具体的类都创建一个单独的工厂,由每个工厂加工某一具体的产品,例如香蕉工厂只生产香蕉,苹果工厂只生产苹果,而简单工厂模式则是所有的具体产品都在一个工厂中生产。不多少说了,继续贴代码,看看我们如何用工厂模式来解决简单工厂模式没有解决的问题。

 

最初依旧只有苹果与香蕉

Fruit.java:

 

package bfactorymethod02;

 

public interface Fruit {

    public void get();

}

 

Apple.java:

 

package bfactorymethod02;

 

import bfactorymethod02.Fruit;

 

public class Apple implements Fruit{

    /*

     * 采集

     */

    public void get(){

       System.out.println("采集苹果");

    }

}

 

Banana.java:

 

package bfactorymethod02;

 

import bfactorymethod02.Fruit;

 

public class Banana implements Fruit{

    /*

     * 采集

     */

    public void get(){

       System.out.println("采集香蕉");

    }

}

 

然后,我们开始建立工厂,首先我们先建立一个抽象的工厂(这很重要,也是很关键的一步)

FruitFactory.java:

 

package bfactorymethod02;

 

public interface FruitFactory {

    public Fruit getFruit();

}

 

很多同学可能会疑问,我们为什么要建立抽象的工厂类,原因很简单,因为我们要为每个具体的产品建立工厂,而要为这些所有的工厂进行简单而有效的管理,我们需要给这些具体的工厂类建立一个父类。

 

然后为苹果和香蕉建立具体的工厂

AppleFactory.java:

 

package bfactorymethod02;

 

public class AppleFactory implements FruitFactory {

 

    @Override

    public Fruit getFruit() {

       // TODO Auto-generated method stub

       return new Apple();

    }

 

}

 

BananaFactory.java:

 

package bfactorymethod02;

 

public class BananaFactory implements FruitFactory{

 

    @Override

    public Fruit getFruit() {

       // TODO Auto-generated method stub

       return new Banana();

    }

 

}

 

OK,此时如果我们要生产苹果或者是香蕉的话,只需要在main.java中这么写道:

package bfactorymethod02;

 

public class MainClass {

    public static void main(String[] args) {

       //获得AppleFactory

       FruitFactory appleFactory = new AppleFactory();

       //通过AppleFactory来获取Apple实例对象

       Fruit apple = appleFactory.getFruit();

       apple.get();

      

       //获得BananaFactory

       FruitFactory bananaFactory = new BananaFactory();

       Fruit banana = bananaFactory.getFruit();

       banana.get();

    }

}

 

如果我们此时想添加梨子的话,只需要添加两个类就可以了

 

Peer.java

 

package bfactorymethod02;

 

import bfactorymethod02.Fruit;

 

public class Pear implements Fruit {

 

    @Override

    public void get() {

       System.out.println("采集梨子");

    }

 

}

 

PearFactory.java:

package bfactorymethod02;

 

public class PearFactory implements FruitFactory {

 

    @Override

    public Fruit getFruit() {

       // TODO Auto-generated method stub

       return new Pear();

    }

 

}

 

OK,虽然工厂模式相对于简单工厂模式,代码量增添了不少,但是却极大地提高了程序的拓展性,因为以后每当增添一种水果的时候,我们只需要添加相应的.java文件就可以了,而不是对原有的文件进行删改。

下面我们简单的对简单工厂模式进行一些总结:

 

工厂方法模式同样属于类的创建型模式又被称为多态工厂模式。工厂方法模式的意义是定义一个创建产品对象的工厂接口,将实际创建工作推迟到子类当中。核心工厂类不再负责产品的创建,这样核心类成为一个抽象工厂角色,仅负责具体工厂子类必须实现的接口,这样进一步抽象化的好处是使得工厂方法模式可以使系统在不修改具体工厂角色的情况下引进新的产品。

 

工厂模式分为四种角色:

 

1.抽象工厂(Creator)角色
工厂方法模式的核心,任何工厂类都必须实现这个接口。

2.具体工厂( Concrete  Creator)角色
具体工厂类是抽象工厂的一个实现,负责实例化产品对象。

3.抽象(Product)角色
工厂方法模式所创建的所有对象的父类,它负责描述所有实例所共有的公共接口。

4.具体产品(Concrete Product)角色
工厂方法模式所创建的具体实例对象

 

 

工厂模式与简单工厂模式的对比:

 

工厂方法模式与简单工厂模式在结构上的不同不是很明显。工厂方法类的核心是一个抽象工厂类,而简单工厂模式把核心放在一个具体类上。

    工厂方法模式之所以有一个别名叫多态性工厂模式是因为具体工厂类都有共同的接口,或者有共同的抽象父类。

当系统扩展需要添加新的产品对象时,仅仅需要添加一个具体对象以及一个具体工厂对象,原有工厂对象不需要进行任何修改,也不需要修改客户端,很好的符合了“开放-封闭”原则。而简单工厂模式在添加新产品对象后不得不修改工厂方法,扩展性不好。

工厂方法模式退化后可以演变成简单工厂模式。

 

 

刚才我们在讨论简单工厂模式与工厂模式的过程中,都只是对某一类水果进行了讨论,例如我们说采摘苹果,采摘香蕉,但是我们并没有说明要采摘什么样的苹果与香蕉,如果此时有很多种不同的苹果,例如黄苹果,青苹果,黄香蕉,青香蕉,我们又该如何的生产呢?好了,我们工厂模式的终极版本终于要出场了——抽象工厂模式!

 

(3)     抽象工厂模式

其实抽象工厂模式的实现方式跟工厂模式的实现方式差不多,只是抽象工厂模式的的具体工厂生产的是某一类产品(产品族),而不是具体的某一产品,不说了,给个高清无码的概念图:

 技术分享

例如,北方的水果就是一个产品族,这个产品族包括北方的苹果,香蕉,梨子……这些水果都是有同一个工厂生产出来的,同样的,青色的水果也是一个产品族,它们由另外一个工厂生产出来。

 

抽象工厂模式是所有形态的工厂模式中最为抽象和最其一般性的。抽象工厂模式可以向客户端提供一个接口,使得客户端在不必指定产品的具体类型的情况下,能够创建多个产品族的产品对象,好了,我们要上代码了。

 

 

首先,我们又苹果,香蕉两个大类,其中有具体分为北方的苹果,北方的香蕉;南方的苹果,南方的香蕉;温室的苹果,温室的香蕉。

 

水果:

Fruit.java:

 

package cabsractfactory01;

 

public interface Fruit {

    public void get();

}

 

苹果:

Apple.java:

 

package cabsractfactory01;

 

import cabsractfactory01.Fruit;

 

public abstract class Apple implements Fruit{

    /*

     * 采集

     */

    public abstract void get();

}

 

香蕉:

Banan.java:

 

package cabsractfactory01;

 

import cabsractfactory01.Fruit;

 

public abstract class Banana implements Fruit{

    /*

     * 采集

     */

    public abstract void get();

}

 

北方的苹果:

NorthApple.java:

 

package cabsractfactory01;

 

public class NorthApple extends Apple {

 

    @Override

    public void get() {

       System.out.println("采集北方苹果");

    }

 

}

 

北方的香蕉:

 

 

package cabsractfactory01;

 

public class NorthBanana extends Banana {

 

    @Override

    public void get() {

       System.out.println("采集北方香蕉");

    }

 

}

 

南方的苹果:略

南方的香蕉:略

温室的苹果:略

温室的香蕉:略

 

抽象工厂类:

 

package cabsractfactory01;

 

public interface FruitFactory {

    public Fruit getApple();

    public Fruit getBanana();

}

 

北方水果工厂类:

package cabsractfactory01;

 

public class NorthFruitFactory implements FruitFactory{

 

    @Override

    public Fruit getApple() {

       return new NorthApple();

    }

 

    @Override

    public Fruit getBanana() {

       return new NorthBanana();

    }

 

}

 

下面我们想得到北方的水果:

 

package cabsractfactory01;

 

public class MainClass {

 

    public static void main(String[] args) {

       //获得北方的水果

       FruitFactory northFruitFactory = new NorthFruitFactory();

       Fruit apple = northFruitFactory.getApple();

       apple.get();

      

       Fruit banana = northFruitFactory.getBanana();

       banana.get();

    }

 

}

 

运行结果:

采集北方苹果

采集北方香蕉

 

好了,关于有关工厂模式的介绍到这里差不多就结束了,我们来简单的总结一下这三种工厂模式的特点

 

简单工厂模式:一个工厂制造所有的物品

工厂模式:一个工厂制造某一具体的物品

抽象工厂模式:一个工厂制造一类物品

 

工厂模式

标签:

原文地址:http://www.cnblogs.com/magicy/p/4631800.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!