设计模式之工厂模式(Java)

来源:互联网 发布:淘宝白菜价群赚钱吗 编辑:程序博客网 时间:2024/06/02 02:33

设计模式是一套反复使用的、多数人知晓的、经过分类编目的、代码设计经验总结。使用设计模式为了提高代码的可重用性,让代码更容易被他人理解,保证代码的可靠性。

一、工厂模式概念

用工厂方法代替new操作来得到一个实例化对象,工厂模式包括简单工厂模式、工厂方法模式和抽象工厂模式,可以认为简单工厂模式是工厂方法模式的特例,抽象工厂模式是工厂方法模式的扩展。
项目中的应用:
在软件系统中经常面临着“对象”的创建工作,由于需求的变化,这个对象可能随之也会发生变化,但它却拥有比较稳定的接口。为此,我们需要提供一种封装机制来隔离出这个异变对象的变化,从而保持系统中其他依赖该对象的对象不随着需求变化而变化。尽量松耦合,一个对象的依赖对象的变化与本身无关,具体产品与客户端剥离,责任分割。

那么在什么样的情况下我们应该记得使用工厂模式呢?大体有两点:
1.在编码时不能预见需要创建哪种类的实例。
2.系统不应依赖于产品类实例如何被创建、组合和表达的细节

For example,恩,以上理论晦涩难懂,举个例子。我们就以某person吃饭为例来说明,在食堂就餐时,某可能会选择粽子、豆腐脑、烤肠,当然也可能会选择其他。除了对食物类别的选择之外,并且还有可能对食物的口味也很挑剔,可能是甜的、咸的、还有辣的等等。这样食堂大师傅就需要对食物的类别与食物的口味进行不同的组合以满足不同客户的需求此时食堂大师傅就充当了工厂的角色,顾客需要什么,就生产什么。
接下来,就工厂方法模式和抽象工厂模式以在食堂吃饭为例进行说明。

二、简单工厂模式

工厂方法模式类图
这里写图片描述

(1)编写食物接口:FoodInterface

package com.tong.Factory;/** * @describe 食物接口 * @author tong * @version 1.0 2017-11-8 */public interface FoodInterface {    /**     * 吃饭     */    void eating();}

(2)食物接口FoodInterface的实现类:豆腐脑Doufunao

package com.tong.Factory;public class Doufunao implements FoodInterface {    /**     * 吃豆腐脑     */    @Override    public void eating() {        System.out.println("***********吃豆腐脑***********");    }}

(3)食物接口FoodInterface的实现类:粽子Zongzi

package com.tong.Factory;public class Zongzi implements FoodInterface {    /**     * 吃粽子     */    @Override    public void eating() {        System.out.println("*************吃粽子***********");    }}

(4)编写工厂类:Canteen

package com.tong.Factory;/** * @describe 食堂 * @author tong * @version 1.0 2017-11-8 */public class Canteen {    /**     * 根据类的名称来生产对象,这里用到了反射机制     * @param className     * @return     */    public FoodInterface getFoodByClass(String className){        try {            FoodInterface food = (FoodInterface) Class.forName(className).newInstance();            return food;        } 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 null;    }}

(5)编写Test类

package com.tong.Factory;public class Test {    public static void main(String[] args) {        Canteen canteen = new Canteen();        FoodInterface food = null;        //吃豆腐脑        food = canteen.getFoodByClass ("com.tong.Factory.Doufunao");        food.eating();        //吃粽子        food = canteen.getFoodByClass ("com.tong.Factory.Zongzi");        food.eating();    }}

(6)输出结果:

***********吃豆腐脑************************吃粽子***********

总结:当我们在需要什么食物时,仅仅实现FoodInterface接口就可以了,客户端新建类的类名就可以得到该食物。

三、工厂方法模式

工厂方法模式类图
这里写图片描述

工厂方法模式去掉了简单工厂模式中工厂方法的静态属性,使得它可以被子类继承。这样在简单工厂模式里集中在工厂方法上的压力可以由工厂方法模式里不同的工厂子类来分担。
工厂方法模式组成:
1)抽象工厂角色: 这是工厂方法模式的核心,它与应用程序无关。是具体工厂角色必须实现的接口或者必须继承的父类。在java中它由抽象类或者接口来实现。
2)具体工厂角色:它含有和具体业务逻辑有关的代码。由应用程序调用以创建对应的具体产品的对象。
3)抽象产品角色:它是具体产品继承的父类或者是实现的接口。在java中一般有抽象类或者接口来实现。
4)具体产品角色:具体工厂角色所创建的对象就是此角色的实例。在java中由具体的类来实现。
还是以上面的例子来讲,如果食物种类的繁多,如果仅仅由食堂的一个人来负责,未免有点任务繁重,这样我们把食堂也定义为是接口,然后由食堂具体的某一位大师傅来具体负责某一种或者几种食物。

** * @describe 工厂接口 * @author tong * @version 1.0 2017-11-8 */public interface CanteenInterface {    void getFood();}/** * @describe 具体工厂 * @author tong * @version 1.0 2017-11-8 */public class DoufunaoDashifu implements CanteenInterface {    @Override    public void getFood(){        FoodInterface food = new Doufunao();        food.eating();    }}/** * @describe 具体工厂 * @author tong * @version 1.0 2017-11-8 */public class ZongziDashifu implements CanteenInterface{    @Override    public void getFood(){        FoodInterface food = new Zongzi();        food.eating();    }}/** * @describe 食物接口 * @author tong * @version 1.0 2017-11-8 */public interface FoodInterface {    /**     * 吃饭     */    void eating();}//具体食物public class Zongzi implements FoodInterface {    /**     * 吃粽子     */    @Override    public void eating() {        System.out.println("*************吃粽子***********");    }}//具体食物public class Doufunao implements FoodInterface {    /**     * 吃豆腐脑     */    @Override    public void eating() {        System.out.println("***********吃豆腐脑***********");    }}

当需要食物时时,只要按照分别对应食物、大师傅,那么就可以被客户使用,而不必去修改任何已有的代码。(即当有新产品时,只要创建并基础抽象产品;新建具体工厂继承抽象工厂;而不用修改任何一个类)工厂方法模式是完全符合开闭原则的!

四、抽象工厂模式

抽象工厂模式类图:
这里写图片描述

先来认识下什么是产品族: 位于不同产品等级结构中,功能相关联的产品组成的家族。
在这里粽子和豆腐脑分别是不同的产品树,甜粽子和甜豆腐脑属于一个产品族,咸粽子和咸豆腐脑属于一个产品族。
可以这么说,它和工厂方法模式的区别就在于需要创建对象的复杂程度上。而且抽象工厂模式是三个里面最为抽象、最具一般性的。抽象工厂模式的用意为:给客户端提供一个接口,可以创建多个产品族中的产品对象。
而且使用抽象工厂模式还要满足一下条件:
1.系统中有多个产品族,而系统一次只可能消费其中一族产品
2.同属于同一个产品族的产品以其使用。
来看看抽象工厂模式的各个角色(和工厂方法的如出一辙):
抽象工厂角色: 这是工厂方法模式的核心,它与应用程序无关。是具体工厂角色必须实现的接口或者必须继承的父类。在java中它由抽象类或者接口来实现。
具体工厂角色:它含有和具体业务逻辑有关的代码。由应用程序调用以创建对应的具体产品的对象。在java中它由具体的类来实现。
抽象产品角色:它是具体产品继承的父类或者是实现的接口。在java中一般有抽象类或者接口来实现。
具体产品角色:具体工厂角色所创建的对象就是此角色的实例。在java中由具体的类来实现。

//抽象产品 豆腐脑public interface Doufunao {    void eating();}
//具体产品public class SaltDoufunao implements Doufunao{    @Override    public void eating() {        System.out.println("************这是咸豆腐脑***********");    }}
//具体产品public class SweetDoufunao implements Doufunao {    @Override    public void eating() {        System.out.println("************这是甜豆腐脑***********");    }}
//抽象产品 粽子public interface Zongzi  {    void eating();}
//具体产品public class SweetZongzi implements Zongzi{    @Override    public void eating() {        System.out.println("************这是甜粽子***********");    }}
//具体产品public class SaltZongzi implements Zongzi{    @Override    public void eating() {        System.out.println("************这是咸粽子***********");    }}
/** * @describe 抽象工厂 * @author tong * @version 1.0 2017-11-8 */public interface FoodFactory {    void getDoufunao();    void getZongzi();}
//具体工厂public class SaltFactorry implements FoodFactory {    @Override    public void getDoufunao() {        Doufunao food = new SaltDoufunao();        food.eating();    }    @Override    public void getZongzi() {        Zongzi food = new SaltZongzi();        food.eating();    }}
//具体工厂public class SweetFactorry implements FoodFactory {    @Override    public void getDoufunao() {        Doufunao food = new SweetDoufunao();        food.eating();    }    @Override    public void getZongzi() {        Zongzi food = new SweetZongzi();        food.eating();    }}

以上的抽象工厂模式,可以利用反射来改进抽象工厂及其子工厂的实现。