Java设计模式圣经连载(01)-简单工厂模式

简介:
1.1 简单工厂(Simple Factory)模式

简单工厂模式是类的创建,又叫静态工厂方法(Static Factory Methord)模式。简单工厂模式是由一个工厂对象决定创造哪一种产品类的实例。
 
1.1.1 工厂模式的几种形态

工厂模式专门负责将大量有共同接口的类实例化。工厂模式可以动态的决定将哪一个类实例化,工厂模式有以下几种形态:
 简单工厂(Simple Factory)模式:又称静态工厂方法(Static Factory Methord)模式。
 工厂方法(Factory Method)模式:又称多态性工厂(Polymorphic Factory)模式或虚拟构造子(Virtual Constructor)模式。
 抽象工厂(Abstract Factory)模式:又称工具箱(Kit或Toolkit)模式。
下图所示的就是简单工厂模式的简略类图。
点击在新窗口查看全图

简单工厂模式,或称静态工厂方法模式,是不同工厂方法模式的一个特殊实现。在Java语言中,通常的工厂方法模式不能通过设计功能的退化给出静态工厂方法模式。
 
1.1.2 简单工厂模式的引进(一般模式)
比如有一个农场,生产各种水果,有苹果(Apple)、草莓(Strawberry)、葡萄(Grape);农场的园丁(FruitGardener)要根据客户的需求,提供相应的水果。下面看看是如何用简单工厂模式实现这个过程的,如下图:
点击在新窗口查看全图

 
此模式的实现源码如下:
 
1.1.2.1 产品接口-水果接口:Fruit.java
package com.lavasoft.patterns.simplefactory.ybgc;
/**
 * Created by IntelliJ IDEA.
 * FileName:Fruit.java
 * User:    LavaSoft
 * Date:    2006-12-1
 * Time:    0:26:51
 * 《Java与模式》(--阎宏博士著)读书笔记
 * 工厂模式模式--简单工厂模式--一般模式
 * ReadMe:  抽象产品角色:工厂的水果产品接口--水果
 */
public interface Fruit {
    /**
     * 种植
     */
    void plant();
    /**
     * 生长
     */
    void grow();
    /**
     * 收获
     */
    void harvest();
}
 
1.1.2.2 产品-平果类:Apple.java
package com.lavasoft.patterns.simplefactory.ybgc;
/**
 * Created by IntelliJ IDEA.
 * FileName:Apple.java
 * User:    LavaSoft
 * Date:    2006-12-1
 * Time:    0:47:25
 * 《Java与模式》(--阎宏博士著)读书笔记
 * 工厂模式模式--简单工厂模式--一般模式
 * ReadMe:  水果工厂的产品:苹果
 */
public class Apple implements Fruit {
    private int treeAge;
    /**
     * 种植
     */
    public void plant() {
        System.out.println("Apple has been planted.");
    }
    /**
     * 生长
     */
    public void grow() {
        System.out.println("Apple is growing...");
    }
    /**
     * 收获
     */
    public void harvest() {
        System.out.println("Apple has been harvested.");
    }
    /**
     * @return 返回树龄
     */
    public int getTreeAge() {
        return treeAge;
    }
    /**
     * 设置树龄
     */
    public void setTreeAge(int treeAge) {
        this.treeAge = treeAge;
    }
}
 
1.1.2.3 产品-草莓类:Strawberry.java
package com.lavasoft.patterns.simplefactory.ybgc;
/**
 * Created by IntelliJ IDEA.
 * FileName:Strawberry.java
 * User:    LavaSoft
 * Date:    2006-12-1
 * Time:    0:45:09
 * 《Java与模式》(--阎宏博士著)读书笔记
 * 工厂模式模式--简单工厂模式--一般模式
 * ReadMe:  水果工厂的产品:草莓
 */
public class Strawberry implements Fruit {
    /**
     * 生长
     */
    public void grow() {
        System.out.println("Strawberry is growing...");
    }
    /**
     * 收获
     */
    public void harvest() {
        System.out.println("Strawberry has been harvested.");
    }
    /**
     * 种植
     */
    public void plant() {
        System.out.println("Strawberry has been planted.");
    }
    /**
     * 辅助方法
     */
    public static void log(String msg) {
        System.out.println(msg);
    }
}
 
1.1.2.4 产品-葡萄类:Grape.java
package com.lavasoft.patterns.simplefactory.ybgc;
/**
 * Created by IntelliJ IDEA.
 * FileName:Grape.java
 * User:    LavaSoft
 * Date:    2006-12-1
 * Time:    0:36:56
 * 《Java与模式》(--阎宏博士著)读书笔记
 * 工厂模式模式--简单工厂模式--一般模式
 * ReadMe:  水果工厂的产品:葡萄
 */
public class Grape implements Fruit {
    private boolean seedless;   //是否有籽
    /**
     * 种植
     */
    public void plant() {
        System.out.println("Grape has been planted.");
    }
    /**
     * 生长
     */
    public void grow() {
        System.out.println("Grape is growing...");
    }
    /**
     * 收获
     */
    public void harvest() {
        System.out.println("Grape has been harvested.");
    }
    /**
     * @return 是否有籽
     */
    public boolean getSeedless() {
        return seedless;
    }
    /**
     * 有无籽的赋值方法
     */
    public void setSeedless(boolean seedless) {
        this.seedless = seedless;
    }
    /**
     * 辅助方法
     */
    public static void log(String msg) {
        System.out.println(msg);
    }
}
 
1.1.2.5 工厂-园丁类:FruitGardener.java
package com.lavasoft.patterns.simplefactory.ybgc;
/**
 * Created by IntelliJ IDEA.
 * FileName:FruitGardener.java
 * User:    LavaSoft
 * Date:    2006-12-1
 * Time:    1:03:27
 * 《Java与模式》(--阎宏博士著)读书笔记
 * 工厂模式模式--简单工厂模式--一般模式
 * ReadMe:  工厂类角色: 水果园丁,生产水果产品
 */
public class FruitGardener {
    /**
     * 静态工厂方法
     * @param which :具体的产品名称
     * @return 一个水果对象
     * @throws BadFruitException
     */
    public static Fruit factory(String which) throws BadFruitException {
        if (which.equalsIgnoreCase("apple")) {
            return new Apple();
        } else if (which.equalsIgnoreCase("strawberry")) {
            return new Strawberry();
        } else if (which.equalsIgnoreCase("grape")) {
            return new Grape();
        } else {
            throw new BadFruitException("Bad fruit request");
        }
    }
}
 
1.1.2.6 工厂异常定义类:BadFruitException.java
package com.lavasoft.patterns.simplefactory.ybgc;
/**
 * Created by IntelliJ IDEA.
 * FileName:BadFruitException.java
 * User:    LavaSoft
 * Date:    2006-12-1
 * Time:    1:04:56
 * 《Java与模式》(--阎宏博士著)读书笔记
 * 工厂模式模式--简单工厂模式--一般模式
 * ReadMe:  工厂的异常处理类
 */
public class BadFruitException extends Exception {
    public BadFruitException(String msg) {
        super(msg);     //调用父类的构造方法
    }
}
 
1.1.2.7 一般工厂模式的测试类
package com.lavasoft.patterns.simplefactory.ybgc;
/**
 * Created by IntelliJ IDEA.
 * FileName:TestApp.java
 * User:    LavaSoft
 * Date:    2006-12-1
 * Time:    1:12:08
 * 《Java与模式》(--阎宏博士著)读书笔记
 * 工厂模式模式--简单工厂模式--一般模式
 * ReadMe:  一般工厂模式的测试类
 */
public class TestApp {
    /**
     * 测试方法
     */
    private void test(String fruitName) {
        try {
            Fruit f = FruitGardener.factory(fruitName);
            System.out.println("恭喜!生产了一个水果对象:" + fruitName);
        } catch (BadFruitException e) {
            System.out.println("对不起!工厂目前不能生产你所要的产品:" + fruitName);
            System.out.println(e.getMessage());     //输出异常信息
            e.printStackTrace();                    //输出异常堆栈信息
        }
    }
    /**
     * 应用入口方法
     */
    public static void main(String args[]) {
        TestApp t = new TestApp();
        t.test("apple");
        t.test("grape");
        t.test("strawberry");
        t.test("car");  //此处会抛异常,水果工厂能生产car(轿车)吗!哈哈哈哈...
    }
}
 
1.1.2.8 测试运行结果
恭喜!生产了一个水果对象:apple
恭喜!生产了一个水果对象:grape
恭喜!生产了一个水果对象:strawberry
对不起!工厂目前不能生产你所要的产品:car
Bad fruit request
com.lavasoft.patterns.simplefactory.ybgc.BadFruitException: Bad fruit request
 at com.lavasoft.patterns.simplefactory.ybgc.FruitGardener.factory(FruitGardener.java:28)
 at com.lavasoft.patterns.simplefactory.ybgc.TestApp.test(TestApp.java:19)
 at com.lavasoft.patterns.simplefactory.ybgc.TestApp.main(TestApp.java:37)
 at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
 at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
 at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
 at java.lang.reflect.Method.invoke(Method.java:585)
 at com.intellij.rt.execution.application.AppMain.main(AppMain.java:90)
Process finished with exit code 0
从结果看来,有异常,是因为输入了工厂不能生产的类型car(小汽车),哈哈哈哈,果园能生产汽车吗?让幼儿园的小朋友告诉你吧!
 
1.1.3 简单工厂模式的一般性结构

 
总结一下,从上面的简单工厂模式的实现可以看到,简单工厂模式需要实现
 工厂角色:园丁
 抽象产品:水果接口
 具体产品:苹果、葡萄、草莓
另外还一般还需要实现
 工厂异常类
 客户类
简单工厂模式的一般性结构图如下:
点击在新窗口查看全图

1.1.4 简单工厂模式的实现
 
1.1.4.1 使用接口或者抽象类实现多层次的产品结构
工厂类可以有多个静态的工厂方法,分别用来生产不同的产品对象。
 
1.1.4.2 多个工厂方法
分别负责创建不同的产品对象,比如java.text.DateFormat类是其子类的工厂类,而DateFormat类就是提供了多个静态工厂方法。
 
1.1.4.3 抽象产品角色的省略
如果系统仅有一个具体产品角色产品角色的话,那么就可以省略掉抽象产品角色。省略掉抽象产品角色后的简略类图如下:
点击在新窗口查看全图

 
下面是一个例子,工厂角色创建具体产品,源代码如下:
 
1.1.4.3.1 产品角色:ConcreteProduct.java
package com.lavasoft.patterns.simplefactory.gchb;
/**
 * Created by IntelliJ IDEA.
 * FileName:ConcreteProduct.java
 * User:    LavaSoft
 * Date:    2006-12-1
 * Time:    2:07:48
 * 《Java与模式》(--阎宏博士著)读书笔记
 * 工厂模式--简单工厂模式--工抽合并(工厂角色与抽象产品角色合并)
 * ReadMe:  具体产品类,表示单一的一类产品.
 */
public class ConcreteProduct {
    public ConcreteProduct() {
    }
}
 
1.1.4.3.2 工厂角色:
package com.lavasoft.patterns.simplefactory.gchb;
/**
 * Created by IntelliJ IDEA.
 * FileName:Creator.java
 * User:    LavaSoft
 * Date:    2006-12-1
 * Time:    1:56:43
 * 《Java与模式》(--阎宏博士著)读书笔记
 * 工厂模式--简单工厂模式--工抽合并(工厂角色与抽象产品角色合并)
 * ReadMe:  具体产品类,与抽象产品角色合并,只生产单一种类产品.
 */
public class Creator {
    /**
     * 静态工厂方法
     * @return 一个产品
     */
    public static Creator factory(){
        return new Creator();
    }
}
 
1.1.4.3.3 测试类
package com.lavasoft.patterns.simplefactory.gchb;
/**
 * Created by IntelliJ IDEA.
 * FileName:TestApp.java
 * User:    LavaSoft
 * Date:    2006-12-1
 * Time:    2:11:30
 * 《Java与模式》(--阎宏博士著)读书笔记
 * 工厂模式--简单工厂模式--工抽合并(工厂角色与抽象产品角色合并)
 * ReadMe:  工抽合并测试类
 */
public class TestApp {
    private void test() {
        Creator t = Creator.factory();
        System.out.println("产品成功生产!");
    }
    public static void main(String args[]) {
        new TestApp().test();
    }
}
 
1.1.4.3.4 测试结果
产品成功生产!
Process finished with exit code 0
 
1.1.4.4 工厂角色与抽象角色合并
在有些情况下,工厂角色可以由抽象产品角色扮演。典型的应用就是java.text.DateFormat类,一个抽象产品类同时是子类的工厂,如下图所示:
点击在新窗口查看全图

 
下面是我自己写的一个实现,源代码如下:
 
1.1.4.4.1 抽象产品类(同时又是工厂类)
package com.lavasoft.patterns.simplefactory.cxsl;
/**
 * Created by IntelliJ IDEA.
 * FileName:AbsProduct.java
 * User:    LavaSoft
 * Date:    2006-12-3
 * Time:    3:23:47
 * 《Java与模式》(--阎宏博士著)读书笔记
 * 工厂模式--简单工厂模式--工厂角色与抽象产品角色合并
 * ReadMe:  抽象产品类,同时又是工厂类.
 */
public abstract class AbsProduct {
    static Product factory(){
        return new Product();
    }
}
 
1.1.4.4.2 具体产品类
package com.lavasoft.patterns.simplefactory.cxsl;
/**
 * Created by IntelliJ IDEA.
 * FileName:Product.java
 * User:    LavaSoft
 * Date:    2006-12-3
 * Time:    3:23:54
 * 《Java与模式》(--阎宏博士著)读书笔记
 * 工厂模式--简单工厂模式--工厂角色与抽象产品角色合并
 * ReadMe:  具体产品类
 */
public class Product {
    Product(){
    }
}
 
1.1.4.4.3 测试类
package com.lavasoft.patterns.simplefactory.cxsl;
/**
 * Created by IntelliJ IDEA.
 * FileName:TestApp.java
 * User:    LavaSoft
 * Date:    2006-12-3
 * Time:    3:30:30
 * 《Java与模式》(--阎宏博士著)读书笔记
 * 工厂模式--简单工厂模式--工厂角色与抽象产品角色合并
 * ReadMe:  测试类
 */
public class TestApp {
    private void test() {
        Product a = AbsProduct.factory();
        System.out.println("成功创建一个产品对象!");
    }
    public static void main(String args[]) {
        TestApp test = new TestApp();
        test.test();
    }
}
 
 
1.1.4.4.4 测试结果

成功创建一个产品对象!
Process finished with exit code 0

 
这个实现很简单,代码就不做详细解释了!
 
1.1.4.5 三个角色全部合并

如果在上面例子的基础上,连抽象产品角色都省略了,而工厂角色就可以与具体产品角色合并。换言之,一个产品类为自身的工厂。如下图所示:
点击在新窗口查看全图

 
下面给出一个简单的实现例子如下:
 
1.1.4.5.1 具体产品类
package com.lavasoft.patterns.simplefactory.sshb;
/**
 * Created by IntelliJ IDEA.
 * FileName:ConcreteProduct.java
 * User:    LavaSoft
 * Date:    2006-12-1
 * Time:    2:20:38
 * 《Java与模式》(--阎宏博士著)读书笔记
 * 工厂模式--简单工厂模式--三色合一模式
 * ReadMe:  抽象产品,产品,工厂类 三和一后的具体产品类
 */
public class ConcreteProduct
{
 public ConcreteProduct(){}
    /**
     * 静态工厂方法
     * @return 具体的产品ConcreteProduct实例
     */
    public static ConcreteProduct factory()
    {
        return new ConcreteProduct();
    }
}
 
1.1.4.5.2 测试类
package com.lavasoft.patterns.simplefactory.sshb;
/**
 * Created by IntelliJ IDEA.
 * FileName:TestApp.java
 * User:    LavaSoft
 * Date:    2006-12-1
 * Time:    2:24:22
 * 《Java与模式》(--阎宏博士著)读书笔记
 * 工厂模式--简单工厂模式--三色合一模式
 * ReadMe:  测试方法
 */
public class TestApp {
    //测试方法
    private void test(){
        ConcreteProduct t=ConcreteProduct.factory();
        System.out.println("产品成功生产!");
    }
    //
    public static void main(String args[]){
        new TestApp().test();
    }
}
 
1.1.4.5.3 测试运行结果
产品成功生产!
Process finished with exit code 0
代码很简单,不解释了。
 
1.1.4.6 产品对象的循环使用和登记式的工厂方法
这里在单例模式和多例模式中在讨论。
简单工厂模式的优点和缺点
 
1.1.4.6.1 简单工厂模式的优点
核心式工厂类,工厂类决定在什么情况下创建哪一种产品类的实例。而客户端则可以免除直接创建产品对象的责任,而仅仅是“消费”产品。简单工厂模式通过这种做法实现了对责任的分割。
 
1.1.4.6.2 简单工厂模式的缺点
当产品类具有复杂的多层次等级结构时,工厂类只有它自己。以不变应万变,是其缺点。
这个工厂类集中了所有产品创建逻辑,形成了一个无所不知的全能类(也称上帝类),如果此类出问题了,整个应用都受大影响。
当产品有多个接口时,判断在什么条件下创建什么产品类实例会很困难。
对于工厂来说,增加新的产品时一个痛苦的过程。工厂角色必须知道每一种产品,如何创建它们,以及何时向客户提供它们。换言之,接纳新的产品意味着修改这个工厂角色的源代码。简单工厂只在有限的程度上支持“开-闭”原则。
由于简单工厂模式使用静态方法作为工厂方法,而静态方法无法由子类继承,因此工厂角色无法形成基于继承的等级结构。这一缺点会在工厂方法模式中得到克服。
 
1.1.4.7 简单工厂模式在Java中的应用
DateFormat与简单工厂模式
SAX2库中的XMLReaderFactory与简单工厂模式
 
1.1.4.8 女娲捏土造人
女娲需要用土造出一个个的人,这就是简单工厂模式的应用,类图如下:
点击在新窗口查看全图

 
女娲是工厂角色,人是抽象产品角色,张三李四是产品。具体实现就不在给出了,参看园丁生产水果的例子。


本文转自 leizhimin 51CTO博客,原文链接:http://blog.51cto.com/lavasoft/11345,如需转载请自行联系原作者
相关文章
|
2月前
|
设计模式 前端开发 搜索推荐
前端必须掌握的设计模式——模板模式
模板模式(Template Pattern)是一种行为型设计模式,父类定义固定流程和步骤顺序,子类通过继承并重写特定方法实现具体步骤。适用于具有固定结构或流程的场景,如组装汽车、包装礼物等。举例来说,公司年会节目征集时,蜘蛛侠定义了歌曲的四个步骤:前奏、主歌、副歌、结尾。金刚狼和绿巨人根据此模板设计各自的表演内容。通过抽象类定义通用逻辑,子类实现个性化行为,从而减少重复代码。模板模式还支持钩子方法,允许跳过某些步骤,增加灵活性。
127 11
|
16天前
|
设计模式
「全网最细 + 实战源码案例」设计模式——模式扩展(配置工厂)
该设计通过配置文件和反射机制动态选择具体工厂,减少硬编码依赖,提升系统灵活性和扩展性。配置文件解耦、反射创建对象,新增产品族无需修改客户端代码。示例中,`CoffeeFactory`类加载配置文件并使用反射生成咖啡对象,客户端调用时只需指定名称即可获取对应产品实例。
76 40
|
17天前
|
设计模式 关系型数据库
「全网最细 + 实战源码案例」设计模式——简单工厂模式
简单工厂模式是一种创建型设计模式,通过工厂类根据传入参数创建不同类型的对象,也称“静态工厂方法”模式。其结构包括工厂类、产品接口和具体产品类。优点是封装性强、代码复用性好;缺点是扩展性差,增加新产品时需修改工厂类代码,违反开闭原则。适用于对象种类较少且调用者无需关心创建细节的场景。
49 19
|
15天前
|
设计模式 Java
「全网最细 + 实战源码案例」设计模式——生成器模式
生成器模式(Builder Pattern)是一种创建型设计模式,用于分步骤构建复杂对象。它允许用户通过控制对象构造的过程,定制对象的组成部分,而无需直接实例化细节。该模式特别适合构建具有多种配置的复杂对象。其结构包括抽象建造者、具体建造者、指挥者和产品角色。适用于需要创建复杂对象且对象由多个部分组成、构造过程需对外隐藏或分离表示与构造的场景。优点在于更好的控制、代码复用和解耦性;缺点是增加复杂性和不适合简单对象。实现时需定义建造者接口、具体建造者类、指挥者类及产品类。链式调用是常见应用方式之一。
49 12
|
17天前
|
设计模式 关系型数据库
「全网最细 + 实战源码案例」设计模式——工厂方法模式
简单工厂模式是一种创建型设计模式,通过一个工厂类根据传入参数创建不同类型的产品对象,也称“静态工厂方法”模式。其结构包括工厂类、产品接口和具体产品类。适用于创建对象种类较少且调用者无需关心创建细节的场景。优点是封装性强、代码复用性好;缺点是扩展性差,增加新产品时需修改工厂类代码,违反开闭原则。
38 15
|
3月前
|
设计模式 消息中间件 搜索推荐
Java 设计模式——观察者模式:从优衣库不使用新疆棉事件看系统的动态响应
【11月更文挑战第17天】观察者模式是一种行为设计模式,定义了一对多的依赖关系,使多个观察者对象能直接监听并响应某一主题对象的状态变化。本文介绍了观察者模式的基本概念、商业系统中的应用实例,如优衣库事件中各相关方的动态响应,以及模式的优势和实际系统设计中的应用建议,包括事件驱动架构和消息队列的使用。
|
3月前
|
设计模式 Java 数据库连接
Java编程中的设计模式:单例模式的深度剖析
【10月更文挑战第41天】本文深入探讨了Java中广泛使用的单例设计模式,旨在通过简明扼要的语言和实际示例,帮助读者理解其核心原理和应用。文章将介绍单例模式的重要性、实现方式以及在实际应用中如何优雅地处理多线程问题。
53 4
|
3月前
|
设计模式 安全 Java
Kotlin - 改良设计模式 - 构建者模式
Kotlin - 改良设计模式 - 构建者模式
|
3月前
|
设计模式 JavaScript Java
Java设计模式:建造者模式详解
建造者模式是一种创建型设计模式,通过将复杂对象的构建过程与表示分离,使得相同的构建过程可以创建不同的表示。本文详细介绍了建造者模式的原理、背景、应用场景及实际Demo,帮助读者更好地理解和应用这一模式。
101 0
|
3月前
|
设计模式 安全 Java
Kotlin教程笔记(51) - 改良设计模式 - 构建者模式
Kotlin教程笔记(51) - 改良设计模式 - 构建者模式