工廠設(shè)計模式案例詳解,不服來辯!
本文轉(zhuǎn)載自微信公眾號「Java極客技術(shù)」,作者鴨血粉絲 。轉(zhuǎn)載本文請聯(lián)系Java極客技術(shù)公眾號。
工廠模式(Factory Pattern)是 Java 中最常用的設(shè)計模式之一,今天我們一起來徹底解析一下它。
一、介紹
從名稱上,顧名思義就是創(chuàng)建產(chǎn)品,按類別分為簡單工廠模式、工廠方法模式、抽象工廠模式,主要功能都是幫助我們把對象的實例化操作單獨抽取出來,優(yōu)化系統(tǒng)架構(gòu),增強(qiáng)系統(tǒng)的擴(kuò)展性。
下面,我們一起來看看各個模式的使用方式。
二、簡單工廠模式
簡單工廠模式,對象創(chuàng)建管理方式最為簡單,因為其僅僅簡單的對不同類對象的創(chuàng)建進(jìn)行了一層薄薄的封裝。該模式通過向工廠傳遞類型來指定要創(chuàng)建的對象。
- 創(chuàng)建一個接口
- public interface Product {
- void operation1();
- void operation2();
- }
- 創(chuàng)建實現(xiàn)接口的實體類
- public class ConcreateProductA implements Product{
- @Override
- public void operation1() {
- System.out.println("產(chǎn)品A,執(zhí)行任務(wù)1");
- }
- @Override
- public void operation2() {
- System.out.println("產(chǎn)品A,執(zhí)行任務(wù)2");
- }
- }
- public class ConcreateProductB implements Product{
- @Override
- public void operation1() {
- System.out.println("產(chǎn)品B,執(zhí)行任務(wù)1");
- }
- @Override
- public void operation2() {
- System.out.println("產(chǎn)品B,執(zhí)行任務(wù)2");
- }
- }
- 創(chuàng)建一個工廠,生成基于給定信息的實體類的對象
- public class SimpleFactory {
- //使用 create 方法獲取形狀類型的對象
- public Product create(String productType){
- if(productType == null){
- return null;
- }
- if(productType.equalsIgnoreCase("productA")){
- return new ConcreateProductA();
- }
- if(productType.equalsIgnoreCase("productB")){
- return new ConcreateProductB();
- }
- return null;
- }
- }
- 編寫客戶端測試類,使用該工廠,通過傳遞類型信息來獲取實體類的對象
- public class FactoryPatternDemo {
- public static void main(String[] args) {
- SimpleFactory simpleFactory = new SimpleFactory();
- //獲取 productA 的對象
- Product productA = simpleFactory.create("productA");
- //調(diào)用 productA 的 operation1、operation2 方法
- productA.operation1();
- productA.operation2();
- //獲取 productB 的對象
- Product productB = simpleFactory.create("productB");
- //調(diào)用 productB 的 operation1、operation2 方法
- productB.operation1();
- productB.operation2();
- }
- }
- 執(zhí)行程序,輸出結(jié)果:
- 產(chǎn)品A,執(zhí)行任務(wù)1
- 產(chǎn)品A,執(zhí)行任務(wù)2
- 產(chǎn)品B,執(zhí)行任務(wù)1
- 產(chǎn)品B,執(zhí)行任務(wù)2
當(dāng)然,還可以將創(chuàng)建對象方式進(jìn)行改進(jìn),將SimpleFactory類創(chuàng)建對象的方式改成如下方式:
- public class SimpleFactory {
- //反射機(jī)制獲取實體類
- public <T> T createByClazzName(Class<? extends T> clazz){
- T obj = null;
- try {
- obj = (T) Class.forName(clazz.getName()).newInstance();
- } catch (Exception e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- }
- return obj;
- }
- }
這樣做的好處是,當(dāng)有新的產(chǎn)品加入時,不用修改工廠類,在調(diào)用的時候,采用如下方式即可獲取對象!
- Product product = new SimpleFactory().create("類名.class");
三、工廠方法模式
和簡單工廠模式中工廠負(fù)責(zé)生產(chǎn)所有產(chǎn)品相比,工廠方法模式將生成具體產(chǎn)品的任務(wù)分發(fā)給具體的產(chǎn)品工廠。
- 創(chuàng)建一個工廠接口
- public interface FactoryProduct {
- Product create();
- }
- 創(chuàng)建實現(xiàn)接口的實體類
- public class ConcreateFactoryA implements FactoryProduct{
- @Override
- public Product create() {
- return new ConcreateProductA();
- }
- }
- public class ConcreateFactoryB implements FactoryProduct{
- @Override
- public Product create() {
- return new ConcreateProductB();
- }
- }
- 編寫客戶端測試類,使用該工廠,通過傳遞類型信息來獲取實體類的對象
- public class FactoryPatternDemo {
- public static void main(String[] args) {
- //獲取 productA 的對象
- Product productA = new ConcreateFactoryA().create();
- //調(diào)用 productA 的 operation1、operation2 方法
- productA.operation1();
- productA.operation2();
- //獲取 productB 的對象
- Product productA = new ConcreateFactoryB().create();
- //調(diào)用 productB 的 operation1、operation2 方法
- productB.operation1();
- productB.operation2();
- }
- }
- 執(zhí)行程序,輸出結(jié)果:
- 產(chǎn)品A,執(zhí)行任務(wù)1
- 產(chǎn)品A,執(zhí)行任務(wù)2
- 產(chǎn)品B,執(zhí)行任務(wù)1
- 產(chǎn)品B,執(zhí)行任務(wù)2
四、抽象工廠模式
抽象工廠模式主要是應(yīng)對產(chǎn)品族概念提出來的。提供一個創(chuàng)建一系列相關(guān)或相互依賴的對象。
- 為形狀創(chuàng)建一個接口
- public interface Shape {
- void draw();
- }
- 創(chuàng)建實現(xiàn)接口的實體類
- public class Rectangle implements Shape {
- @Override
- public void draw() {
- System.out.println("Inside Rectangle::draw() method.");
- }
- }
- public class Square implements Shape {
- @Override
- public void draw() {
- System.out.println("Inside Square::draw() method.");
- }
- }
- public class Circle implements Shape {
- @Override
- public void draw() {
- System.out.println("Inside Circle::draw() method.");
- }
- }
- 為顏色創(chuàng)建一個接口
- public interface Color {
- void fill();
- }
- 創(chuàng)建實現(xiàn)接口的實體類
- public class Red implements Color {
- @Override
- public void fill() {
- System.out.println("Inside Red::fill() method.");
- }
- }
- public class Green implements Color {
- @Override
- public void fill() {
- System.out.println("Inside Green::fill() method.");
- }
- }
- public class Blue implements Color {
- @Override
- public void fill() {
- System.out.println("Inside Blue::fill() method.");
- }
- }
- 為 Color 和 Shape 對象創(chuàng)建抽象類來獲取工廠
- public abstract class AbstractFactory {
- public abstract Color getColor(String color);
- public abstract Shape getShape(String shape) ;
- }
- 創(chuàng)建擴(kuò)展了 AbstractFactory 的工廠類,基于給定的信息生成實體類的對象
- public class ShapeFactory extends AbstractFactory {
- @Override
- public Shape getShape(String shapeType){
- if(shapeType == null){
- return null;
- }
- if(shapeType.equalsIgnoreCase("CIRCLE")){
- return new Circle();
- } else if(shapeType.equalsIgnoreCase("RECTANGLE")){
- return new Rectangle();
- } else if(shapeType.equalsIgnoreCase("SQUARE")){
- return new Square();
- }
- return null;
- }
- @Override
- public Color getColor(String color) {
- return null;
- }
- }
- public class ColorFactory extends AbstractFactory {
- @Override
- public Shape getShape(String shapeType){
- return null;
- }
- @Override
- public Color getColor(String color) {
- if(color == null){
- return null;
- }
- if(color.equalsIgnoreCase("RED")){
- return new Red();
- } else if(color.equalsIgnoreCase("GREEN")){
- return new Green();
- } else if(color.equalsIgnoreCase("BLUE")){
- return new Blue();
- }
- return null;
- }
- }
- 創(chuàng)建一個工廠創(chuàng)造器/生成器類,通過傳遞形狀或顏色信息來獲取工廠
- public class FactoryProducer {
- public static AbstractFactory getFactory(String choice){
- if(choice.equalsIgnoreCase("SHAPE")){
- return new ShapeFactory();
- } else if(choice.equalsIgnoreCase("COLOR")){
- return new ColorFactory();
- }
- return null;
- }
- }
- 使用 FactoryProducer 來獲取 AbstractFactory,通過傳遞類型信息來獲取實體類的對象
- public class AbstractFactoryPatternDemo {
- public static void main(String[] args) {
- //獲取形狀工廠
- AbstractFactory shapeFactory = FactoryProducer.getFactory("SHAPE");
- //獲取形狀為 Circle 的對象
- Shape shape1 = shapeFactory.getShape("CIRCLE");
- //調(diào)用 Circle 的 draw 方法
- shape1.draw();
- //獲取形狀為 Rectangle 的對象
- Shape shape2 = shapeFactory.getShape("RECTANGLE");
- //調(diào)用 Rectangle 的 draw 方法
- shape2.draw();
- //獲取形狀為 Square 的對象
- Shape shape3 = shapeFactory.getShape("SQUARE");
- //調(diào)用 Square 的 draw 方法
- shape3.draw();
- //獲取顏色工廠
- AbstractFactory colorFactory = FactoryProducer.getFactory("COLOR");
- //獲取顏色為 Red 的對象
- Color color1 = colorFactory.getColor("RED");
- //調(diào)用 Red 的 fill 方法
- color1.fill();
- //獲取顏色為 Green 的對象
- Color color2 = colorFactory.getColor("Green");
- //調(diào)用 Green 的 fill 方法
- color2.fill();
- //獲取顏色為 Blue 的對象
- Color color3 = colorFactory.getColor("BLUE");
- //調(diào)用 Blue 的 fill 方法
- color3.fill();
- }
- }
- 執(zhí)行程序,輸出結(jié)果:
- Inside Circle::draw() method.
- Inside Rectangle::draw() method.
- Inside Square::draw() method.
- Inside Red::fill() method.
- Inside Green::fill() method.
- Inside Blue::fill() method.
五、應(yīng)用
工廠模式在實際開發(fā)中使用非常頻繁,例如 JDK 中的日歷操作,在國際化的時候,獲取本地語言就用到簡單工廠模式。
寫一個獲取測試,如下:
- public static void main(String[] args) {
- //獲取日歷操作類
- Calendar calendar = Calendar.getInstance();
- int year = calendar.get(Calendar.YEAR);
- // 取月份要加1
- int month = calendar.get(Calendar.MONTH) + 1;
- int day = calendar.get(Calendar.DAY_OF_MONTH);
- int hour = calendar.get(Calendar.HOUR_OF_DAY);
- int minute = calendar.get(Calendar.MINUTE);
- int seconds = calendar.get(Calendar.SECOND);
- // 1-7分別代表 -- 星期日,星期一,星期二,星期三,星期四,星期五,星期六
- int week = calendar.get(calendar.DAY_OF_WEEK);
- // 年-月-日
- System.out.println("year = " + year);
- System.out.println("month = " + month);
- System.out.println("day = " + day);
- //時-分-秒
- System.out.println("hour = " + hour);
- System.out.println("minute = " + minute);
- System.out.println("seconds = " + seconds);
- // 星期
- System.out.println("week = " + week);
- }
進(jìn)入getInstance()方法,在獲取日歷類型的時候,內(nèi)容如下:
六、小結(jié)
工廠模式中,重要的是工廠類,而不是產(chǎn)品類。產(chǎn)品類可以是多種形式,多層繼承或者是單個類都是可以的。
但要明確的,工廠模式的接口只會返回一種類型的實例,這是在設(shè)計產(chǎn)品類的時候需要注意的,最好是有父類或者共同實現(xiàn)的接口。
上面介紹的三種工廠模式有各自的應(yīng)用場景,實際應(yīng)用時能解決問題滿足需求即可!
七、參考
1、菜鳥教程 - 工廠模式
2、博客園 - alpha_panda - 設(shè)計模式之工廠模式