1. 程式人生 > >(原創)我眼中的設計模式系列之簡單工廠模式(一)

(原創)我眼中的設計模式系列之簡單工廠模式(一)

int 業務 text 們的 acc 現在 rgs sub reat

簡單工廠模式

  在日常的軟件開發中,我們一般都是按照模塊來劃分工作的。

場景一:

  試想我們現在有這麽一個模塊,為其他的模塊提供服務,比如說我們調用了好幾個外部接口,統一返回XML字符串,每個接口返回的XML格式都不同,有的嵌套數組,有的純數組,有的就是普通的節點XML。但是我們項目需要的是json格式的數據,通常的做法是寫幾個類,直接new出對象調用,或者交給spring管理進行註入。不管如何這幾個解析類都不是在同一個環境中,即使交由Spring管理,就站在這個模塊的角度中來說,這幾個類並並沒有形成自己的模塊化數據結構,而是分開和Spring的環境分散的耦合在一起了。代碼的結構會非常差。


場景二:

  我們的業務模塊中需要的類有可能是不相關的,毫無聯系的,但是我們在一個比較大型的功能中需要同時用到這些類中的行為,這個時候我認為是可以使用工廠模式。即這些類實現同一個接口,使用工廠去維護他們,只針對我們需要的業務模塊的維護,工廠類可以交給Spring管理,作為這個工廠和Spirng的接口,相當於跟Spring的環境有關系但是又不耦合。

  下面我舉個小例子可以說明工廠模式的使用,直接上代碼:

先創建具體行為的Animal接口

package com.bane.example1.executor;

/**
 * 
* @ClassName: Animal 
* @Description: TODO(定義動物的接口) 
* 
@author 於繼偉 * @date 2017-10-20 下午10:06:49 * */ public interface Animal { }

創建具體動物行為的接口:

package com.bane.example1.executor;

/**
 * 
* @ClassName: CatExecutor 
* @Description: TODO(Cat的行為接口) 
* @author 於繼偉
* @date 2017-10-20 下午10:02:29 
*
 */
public interface CatExecutor extends Animal {
    
    /**
     * 抓老鼠的行為
     
*/ void catchMouse(); }
package com.bane.example1.executor;

/**
 * 
* @ClassName: DogExecutor 
* @Description: TODO(Dog的行為接口) 
* @author 於繼偉
* @date 2017-10-20 下午10:00:12 
*
 */
public interface DogExecutor extends Animal {
    
    /**
     * 看家的方法
     */
    void door();
    
}
package com.bane.example1.executor;

/**
 * 
* @ClassName: SnakeExecutor 
* @Description: TODO(Snake的行為接口) 
* @author 於繼偉
* @date 2017-10-20 下午10:04:46 
*
 */
public interface SnakeExecutor extends Animal {
    
    /**
     * 咬人的行為
     */
    void bite();
    
}

再創建具體的實現:

package com.bane.example1.executor.impl;

import com.bane.example1.executor.CatExecutor;

/**
 * 
* @ClassName: CatExecutorImpl 
* @Description: TODO(貓具體行為的實現) 
* @author 於繼偉
* @date 2017-10-20 下午10:09:11 
*
 */
public class CatExecutorImpl implements CatExecutor {
    
    @Override
    public void catchMouse() {
        System.out.println("抓老鼠");
    }
    
}
package com.bane.example1.executor.impl;

import com.bane.example1.executor.DogExecutor;

/**
 * 
* @ClassName: DogExecutorImpl 
* @Description: TODO(狗的行為的具體實現) 
* @author 於繼偉
* @date 2017-10-20 下午10:09:08 
*
 */
public class DogExecutorImpl implements DogExecutor{
    
    @Override
    public void door() {
        System.out.println("狗看家");
    }
    
}
package com.bane.example1.executor.impl;

import com.bane.example1.executor.SnakeExecutor;

/**
 * 
* @ClassName: SnakeExecutorImpl 
* @Description: TODO(蛇具體行為) 
* @author 於繼偉
* @date 2017-10-20 下午10:11:19 
*
 */
public class SnakeExecutorImpl implements SnakeExecutor {
    
    @Override
    public void bite() {
        System.out.println("蛇咬人");
    }
    
}

工廠環境中的具體行為者有了,現在創建工廠的接口和實現:

package com.bane.example1.factory;

import com.bane.example1.executor.Animal;

/**
 * 
* @ClassName: AnimalFactory 
* @Description: TODO(簡單工廠接口) 
* @author 於繼偉
* @date 2017-10-20 下午9:57:46 
*
 */
public interface AnimalFactory {
    
    /**
     * 根據類名創建Animal對象
     * @param className
     * @return
     */
    Animal createAnimal(String className);
    
}
package com.bane.example1.factory.impl;

import com.bane.example1.executor.Animal;
import com.bane.example1.factory.AnimalFactory;

/**
 * 
* @ClassName: AnimalFactoryImpl 
* @Description: TODO(動物工廠的具體實現) 
* @author 於繼偉
* @date 2017-10-20 下午10:14:03 
*
 */
public class AnimalFactoryImpl implements AnimalFactory {
    
    @Override
    public Animal createAnimal(String className) {
        
        Animal animal = null;
        try {
            animal = (Animal) Class.forName(className).newInstance();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
        
        return animal;
    }
    
}

到此為止,我們的簡單工廠創建結束,將動物放入動物的工廠中,我們需要用的時候只需要從工廠中獲取動物的實例和行為,就可以使用了,測試類:

package com.bane.example1;

import com.bane.example1.executor.CatExecutor;
import com.bane.example1.executor.DogExecutor;
import com.bane.example1.executor.SnakeExecutor;
import com.bane.example1.factory.AnimalFactory;
import com.bane.example1.factory.impl.AnimalFactoryImpl;

/**
 * 
* @ClassName: Main 
* @Description: TODO(主方法測試) 
* @author 於繼偉
* @date 2017-10-20 下午10:21:48 
*
 */
public class Main {
    
    public static void main(String[] args) {
        
        AnimalFactory animalFactory = new AnimalFactoryImpl();
        
        CatExecutor catExecutor = (CatExecutor) animalFactory.
                createAnimal("com.bane.example1.executor.impl.CatExecutorImpl");
        catExecutor.catchMouse();
        
        DogExecutor dogExecutor = (DogExecutor) animalFactory.
        createAnimal("com.bane.example1.executor.impl.DogExecutorImpl");
        dogExecutor.door();
        
        SnakeExecutor snakeExecutor = (SnakeExecutor) animalFactory.
        createAnimal("com.bane.example1.executor.impl.SnakeExecutorImpl");
        snakeExecutor.bite();
    }
    
}

控制臺輸出如下:

抓老鼠
狗看家
蛇咬人

需要說明的是,我們是用類名利用反射創建的實例,這樣可以省去if else的判斷,代碼更加優雅。至於需要用什麽樣的方式去創建或者什麽樣的條件,這個可以自己靈活使用。至此,簡單工廠到此為止。

 靜態工廠

  靜態工廠,其實跟上面的簡單工廠沒有任何的區別,無疑是工廠類中構造方法是私有的,方法都是靜態的。直接上代碼:

創建顏色的接口和具體的顏色實現:

package com.bane.example2.executor;

/**
 * 
* @ClassName: Color 
* @Description: TODO(定義顏色行為接口) 
* @author 於繼偉
* @date 2017-10-21 下午12:11:28 
*
 */
public interface Color {
    
    void show();
    
}

具體實現:

package com.bane.example2.executor.impl;

import com.bane.example2.executor.Color;

/**
 * 
* @ClassName: Blue 
* @Description: TODO(Blue具體實現) 
* @author 於繼偉
* @date 2017-10-21 下午12:13:17 
*
 */
public class Blue implements Color{
    
    @Override
    public void show() {
        System.out.println("這是藍色");
    }
    
}
package com.bane.example2.executor.impl;

import com.bane.example2.executor.Color;

/**
 * 
* @ClassName: Red 
* @Description: TODO(Red具體實現) 
* @author 於繼偉
* @date 2017-10-21 下午12:12:43 
*
 */
public class Red implements Color{
    
    @Override
    public void show() {
        System.out.println("我是紅色");
    }
    
}
package com.bane.example2.executor.impl;

import com.bane.example2.executor.Color;

/**
 * 
* @ClassName: Yellow 
* @Description: TODO(Yellow具體實現) 
* @author 於繼偉
* @date 2017-10-21 下午12:13:51 
*
 */
public class Yellow implements Color{
    
    @Override
    public void show() {
        System.out.println("這是黃色");
    }
    
}

最後創建我們的靜態工廠:

package com.bane.example2.factory;

import com.bane.example2.executor.Color;

/**
 * 
* @ClassName: ColorFactory 
* @Description: TODO(靜態工廠實現) 
* @author 於繼偉
* @date 2017-10-21 下午12:16:49 
*
 */
public class ColorFactory {
    
    private ColorFactory(){}
    
    /**
     * 靜態工廠獲取Color對象的方法
     * @param className
     * @return
     */
    public static Color createColor(String className){
        Color color = null;
        try {
            color = (Color) Class.forName(className).newInstance();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
        
        return color;
    }
    
}

最後主方法測試靜態工廠:

package com.bane.example2;

import com.bane.example2.executor.Color;
import com.bane.example2.factory.ColorFactory;

/**
 * 
* @ClassName: Main 
* @Description: TODO(主方法測試靜態工廠) 
* @author 於繼偉
* @date 2017-10-21 下午12:19:14 
*
 */
public class Main {
    
    public static void main(String[] args) {
        
        Color blue = ColorFactory.createColor
                ("com.bane.example2.executor.impl.Blue");
        blue.show();
        
        Color red = ColorFactory.createColor
                ("com.bane.example2.executor.impl.Red");
        red.show();
        
        Color yellow = ColorFactory.createColor
                ("com.bane.example2.executor.impl.Yellow");
        yellow.show();
        
    }
    
}

控制臺輸出:

package com.bane.example2;

import com.bane.example2.executor.Color;
import com.bane.example2.factory.ColorFactory;

/**
 * 
* @ClassName: Main 
* @Description: TODO(主方法測試靜態工廠) 
* @author 於繼偉
* @date 2017-10-21 下午12:19:14 
*
 */
public class Main {
    
    public static void main(String[] args) {
        
        Color blue = ColorFactory.createColor
                ("com.bane.example2.executor.impl.Blue");
        blue.show();
        
        Color red = ColorFactory.createColor
                ("com.bane.example2.executor.impl.Red");
        red.show();
        
        Color yellow = ColorFactory.createColor
                ("com.bane.example2.executor.impl.Yellow");
        yellow.show();
        
    }
    
}

控制臺輸出:

這是藍色
我是紅色
這是黃色

至此,靜態工廠結束。

抽象工廠

  抽象工廠其實就是集中了好幾種的工廠,常用的例子是我們的家有廚房,衛生間,房間。這三個都可以看作工廠。廚房裏有菜刀,鍋等等,是具體的事物行為;衛生間有馬桶,淋浴頭等具體的事物行為;房間有衣櫃,床等具體的行為。今天我舉了一個更容易理解的例子。我們的公司有各個部門,例如行政部管的是後勤服務等等,財務部管的是財務和結算等等,開發部負責軟件的開發。公司就是一個抽象工廠,而這三個部門就是抽象工廠的具體工廠,抽象工廠定義行為,具體的工廠實現行為。至於我們剛才說的具體三個部門作為工廠,其實,每個部門內部還有很多員工和級別,這又可以繼續往下分和擴展,但是我們一般不會那麽做。因為那樣類的結構過於復雜,跟我們設計模式的初衷不相符。下面直接上代碼:

創建Department接口,沒有任何行為,主要是為了統一部門的表現形式

package com.bane.example3.executor;

/**
 * 
* @ClassName: Company 
* @Description: TODO(公司的接口) 
* @author 於繼偉
* @date 2017-10-21 下午12:36:38 
*
 */
public interface Department {
}

具體部門接口:

package com.bane.example3.executor;

/**
 * 
* @ClassName: CaiWuBuExecutor 
* @Description: TODO(財務部的行為接口) 
* @author 於繼偉
* @date 2017-10-21 下午12:29:14 
*
 */
public interface CaiWuBuExecutor extends Department{
    
    /**
     * 結算的方法
     */
    void jiesuan();
    
}    
package com.bane.example3.executor;

/**
 * 
* @ClassName: KaiFabuExecutor 
* @Description: TODO(開發部的行為接口) 
* @author 於繼偉
* @date 2017-10-21 下午12:28:42 
*
 */
public interface KaiFabuExecutor extends Department {
    
    /**
     * 開發的方法
     */
    void kaifa();
    
}
package com.bane.example3.executor;

/**
 * 
* @ClassName: XingZhengBuExecutor 
* @Description: TODO(行政部的行為接口) 
* @author 於繼偉
* @date 2017-10-21 下午12:29:33 
*
 */
public interface XingZhengBuExecutor extends Department {
    
    /**
     * 後勤的方法
     */
    void houqin();
    
}

部門的具體實現:

package com.bane.example3.executor.impl;

import com.bane.example3.executor.CaiWuBuExecutor;

/**
 * 
* @ClassName: CaiWuBuExecutorImpl 
* @Description: TODO(財務部具體實現) 
* @author 於繼偉
* @date 2017-10-21 下午12:47:44 
*
 */
public class CaiWuBuExecutorImpl implements CaiWuBuExecutor {

    @Override
    public void jiesuan() {
        System.out.println("財務部負責結算");
    }
    
}
package com.bane.example3.executor.impl;

import com.bane.example3.executor.KaiFabuExecutor;

/**
 * 
* @ClassName: KaiFabuExecutorImpl 
* @Description: TODO(開發部具體實現) 
* @author 於繼偉
* @date 2017-10-21 下午12:48:17 
*
 */
public class KaiFabuExecutorImpl implements KaiFabuExecutor {

    @Override
    public void kaifa() {
        System.out.println("開發部負責開發");
    }
    
    
    
}
package com.bane.example3.executor.impl;

import com.bane.example3.executor.XingZhengBuExecutor;

/**
 * 
* @ClassName: XingZhengBuExecutorImpl 
* @Description: TODO(行政部具體實現) 
* @author 於繼偉
* @date 2017-10-21 下午12:48:48 
*
 */
public class XingZhengBuExecutorImpl implements XingZhengBuExecutor {

    @Override
    public void houqin() {
        System.out.println("行政部負責後勤");
    }
    
}

跟之前一樣,具體的行為有了,可以定義工廠類了:

package com.bane.example3.factory;

import com.bane.example3.executor.CaiWuBuExecutor;
import com.bane.example3.executor.KaiFabuExecutor;
import com.bane.example3.executor.XingZhengBuExecutor;

/**
 * 
* @ClassName: AbstractFactory 
* @Description: TODO(抽象工廠) 
* @author 於繼偉
* @date 2017-10-21 下午12:23:46 
*
 */
public abstract class AbstractCompanyFactory {
    
    /**
     * 構建財務部
     * @param className
     * @return
     */
    public CaiWuBuExecutor createCaiwuBu(String className){return null;}
    
    /**
     * 構建開發部
     * @param className
     * @return
     */
    public KaiFabuExecutor createKaiFabu(String className){return null;}
    
    /**
     * 構建行政部
     * @param className
     * @return
     */
    public XingZhengBuExecutor createXingZhengBu(String className){return null;}
    
}
package com.bane.example3.factory.sub;

import com.bane.example3.executor.CaiWuBuExecutor;
import com.bane.example3.executor.Department;
import com.bane.example3.factory.AbstractCompanyFactory;

/**
 * 
* @ClassName: CaiWuBuFactory 
* @Description: TODO(財務部的工廠) 
* @author 於繼偉
* @date 2017-10-21 下午12:26:53 
*
 */
public class CaiWuBuFactory extends AbstractCompanyFactory {

    @Override
    public CaiWuBuExecutor createCaiwuBu(String className) {
        Department department = null;
        try {
            department = (Department) Class.forName(className).newInstance();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
        return (CaiWuBuExecutor) department;
    }

}
package com.bane.example3.factory.sub;

import com.bane.example3.executor.Department;
import com.bane.example3.executor.KaiFabuExecutor;
import com.bane.example3.factory.AbstractCompanyFactory;

/**
 * 
* @ClassName: KaiFaBuFactory 
* @Description: TODO(開發部的工廠) 
* @author 於繼偉
* @date 2017-10-21 下午12:25:53 
*
 */
public class KaiFaBuFactory extends AbstractCompanyFactory {

    @Override
    public KaiFabuExecutor createKaiFabu(String className) {
        Department department = null;
        try {
            department = (Department) Class.forName(className).newInstance();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
        return (KaiFabuExecutor) department;
    }

}
package com.bane.example3.factory.sub;

import com.bane.example3.executor.Department;
import com.bane.example3.executor.XingZhengBuExecutor;
import com.bane.example3.factory.AbstractCompanyFactory;

/**
 * 
* @ClassName: XingZhengBuFactory 
* @Description: TODO(行政部的工廠) 
* @author 於繼偉
* @date 2017-10-21 下午12:26:12 
*
 */
public class XingZhengBuFactory extends AbstractCompanyFactory{

    @Override
    public XingZhengBuExecutor createXingZhengBu(String className) {
        Department department = null;
        try {
            department = (Department) Class.forName(className).newInstance();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
        return (XingZhengBuExecutor) department;
    }

}

最後寫主方法測試:

package com.bane.example3;

import com.bane.example3.executor.CaiWuBuExecutor;
import com.bane.example3.executor.KaiFabuExecutor;
import com.bane.example3.executor.XingZhengBuExecutor;
import com.bane.example3.factory.AbstractCompanyFactory;
import com.bane.example3.factory.sub.CaiWuBuFactory;
import com.bane.example3.factory.sub.KaiFaBuFactory;
import com.bane.example3.factory.sub.XingZhengBuFactory;

/**
 * 
* @ClassName: Main 
* @Description: TODO(抽象工廠測試) 
* @author 於繼偉
* @date 2017-10-21 下午12:22:48 
*
 */
public class Main {
    
    public static void main(String[] args) {
        //1.獲取具體的工廠
        //財務部的工廠
        AbstractCompanyFactory caiwuFactory = new CaiWuBuFactory();
        
        //開發部的工廠
        AbstractCompanyFactory kaifaFactory = new KaiFaBuFactory();
        
        //行政部的工廠
        AbstractCompanyFactory xingZhengFactory = new XingZhengBuFactory();
        
        //2.從工廠中獲取具體的部門職能
        //財務職能
        CaiWuBuExecutor caiwu = caiwuFactory.createCaiwuBu
                ("com.bane.example3.executor.impl.CaiWuBuExecutorImpl");
        
        //開發職能
        KaiFabuExecutor kaifa = kaifaFactory.createKaiFabu
                ("com.bane.example3.executor.impl.KaiFabuExecutorImpl");
        
        //後勤職能
        XingZhengBuExecutor xingzheng = xingZhengFactory.createXingZhengBu
                ("com.bane.example3.executor.impl.XingZhengBuExecutorImpl");
        
        caiwu.jiesuan();
        kaifa.kaifa();
        xingzheng.houqin();
    }
    
}

控制臺輸出:

財務部負責結算
開發部負責開發
行政部負責後勤

  上面就是我們工廠模式常用的三種表現形式,從上面的代碼我們不難看出接口的作用,面向接口編程是JAVA開發中非常重要的一個理念,或者說是思想,根據SOA的思想來說,暴露出來的一定是接口,接口實現的對象類型的控制和擴展,在面向對象程序的設計中具有非常至關重要的意義。至於面向接口編程,大家可以搜索一下相關的文章去閱讀。

  其實我們的Spring就是一個非常大的工廠模式,閱讀過源碼的同學可以知道,Spring基於BeanFactory,創建出Bean,但是又維護著自己的數據結構,源於工廠,但是比工廠的設計復雜太多太多。工廠模式我的理解就是這樣。

(原創)我眼中的設計模式系列之簡單工廠模式(一)