Java设计模式圣经连载(01)-简单工厂模式_java设计模式 有一个农场,生产各种水果,有苹果,草莓,葡萄,农场的园丁要根据客户的-程序员宅基地

技术标签: date  apple  java  产品  读书  设计模式  

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 女娲捏土造人
女娲需要用土造出一个个的人,这就是简单工厂模式的应用,类图如下:
点击在新窗口查看全图

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

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/bboyfeiyu/article/details/7438127

智能推荐

c# 调用c++ lib静态库_c#调用lib-程序员宅基地

文章浏览阅读2w次,点赞7次,收藏51次。四个步骤1.创建C++ Win32项目动态库dll 2.在Win32项目动态库中添加 外部依赖项 lib头文件和lib库3.导出C接口4.c#调用c++动态库开始你的表演...①创建一个空白的解决方案,在解决方案中添加 Visual C++ , Win32 项目空白解决方案的创建:添加Visual C++ , Win32 项目这......_c#调用lib

deepin/ubuntu安装苹方字体-程序员宅基地

文章浏览阅读4.6k次。苹方字体是苹果系统上的黑体,挺好看的。注重颜值的网站都会使用,例如知乎:font-family: -apple-system, BlinkMacSystemFont, Helvetica Neue, PingFang SC, Microsoft YaHei, Source Han Sans SC, Noto Sans CJK SC, W..._ubuntu pingfang

html表单常见操作汇总_html表单的处理程序有那些-程序员宅基地

文章浏览阅读159次。表单表单概述表单标签表单域按钮控件demo表单标签表单标签基本语法结构<form action="处理数据程序的url地址“ method=”get|post“ name="表单名称”></form><!--action,当提交表单时,向何处发送表单中的数据,地址可以是相对地址也可以是绝对地址--><!--method将表单中的数据传送给服务器处理,get方式直接显示在url地址中,数据可以被缓存,且长度有限制;而post方式数据隐藏传输,_html表单的处理程序有那些

PHP设置谷歌验证器(Google Authenticator)实现操作二步验证_php otp 验证器-程序员宅基地

文章浏览阅读1.2k次。使用说明:开启Google的登陆二步验证(即Google Authenticator服务)后用户登陆时需要输入额外由手机客户端生成的一次性密码。实现Google Authenticator功能需要服务器端和客户端的支持。服务器端负责密钥的生成、验证一次性密码是否正确。客户端记录密钥后生成一次性密码。下载谷歌验证类库文件放到项目合适位置(我这边放在项目Vender下面)https://github.com/PHPGangsta/GoogleAuthenticatorPHP代码示例://引入谷_php otp 验证器

【Python】matplotlib.plot画图横坐标混乱及间隔处理_matplotlib更改横轴间距-程序员宅基地

文章浏览阅读4.3k次,点赞5次,收藏11次。matplotlib.plot画图横坐标混乱及间隔处理_matplotlib更改横轴间距

docker — 容器存储_docker 保存容器-程序员宅基地

文章浏览阅读2.2k次。①Storage driver 处理各镜像层及容器层的处理细节,实现了多层数据的堆叠,为用户 提供了多层数据合并后的统一视图②所有 Storage driver 都使用可堆叠图像层和写时复制(CoW)策略③docker info 命令可查看当系统上的 storage driver主要用于测试目的,不建议用于生成环境。_docker 保存容器

随便推点

网络拓扑结构_网络拓扑csdn-程序员宅基地

文章浏览阅读834次,点赞27次,收藏13次。网络拓扑结构是指计算机网络中各组件(如计算机、服务器、打印机、路由器、交换机等设备)及其连接线路在物理布局或逻辑构型上的排列形式。这种布局不仅描述了设备间的实际物理连接方式,也决定了数据在网络中流动的路径和方式。不同的网络拓扑结构影响着网络的性能、可靠性、可扩展性及管理维护的难易程度。_网络拓扑csdn

JS重写Date函数,兼容IOS系统_date.prototype 将所有 ios-程序员宅基地

文章浏览阅读1.8k次,点赞5次,收藏8次。IOS系统Date的坑要创建一个指定时间的new Date对象时,通常的做法是:new Date("2020-09-21 11:11:00")这行代码在 PC 端和安卓端都是正常的,而在 iOS 端则会提示 Invalid Date 无效日期。在IOS年月日中间的横岗许换成斜杠,也就是new Date("2020/09/21 11:11:00")通常为了兼容IOS的这个坑,需要做一些额外的特殊处理,笔者在开发的时候经常会忘了兼容IOS系统。所以就想试着重写Date函数,一劳永逸,避免每次ne_date.prototype 将所有 ios

如何将EXCEL表导入plsql数据库中-程序员宅基地

文章浏览阅读5.3k次。方法一:用PLSQL Developer工具。 1 在PLSQL Developer的sql window里输入select * from test for update; 2 按F8执行 3 打开锁, 再按一下加号. 鼠标点到第一列的列头,使全列成选中状态,然后粘贴,最后commit提交即可。(前提..._excel导入pl/sql

Git常用命令速查手册-程序员宅基地

文章浏览阅读83次。Git常用命令速查手册1、初始化仓库git init2、将文件添加到仓库git add 文件名 # 将工作区的某个文件添加到暂存区 git add -u # 添加所有被tracked文件中被修改或删除的文件信息到暂存区,不处理untracked的文件git add -A # 添加所有被tracked文件中被修改或删除的文件信息到暂存区,包括untracked的文件...

分享119个ASP.NET源码总有一个是你想要的_千博二手车源码v2023 build 1120-程序员宅基地

文章浏览阅读202次。分享119个ASP.NET源码总有一个是你想要的_千博二手车源码v2023 build 1120

【C++缺省函数】 空类默认产生的6个类成员函数_空类默认产生哪些类成员函数-程序员宅基地

文章浏览阅读1.8k次。版权声明:转载请注明出处 http://blog.csdn.net/irean_lau。目录(?)[+]1、缺省构造函数。2、缺省拷贝构造函数。3、 缺省析构函数。4、缺省赋值运算符。5、缺省取址运算符。6、 缺省取址运算符 const。[cpp] view plain copy_空类默认产生哪些类成员函数

推荐文章

热门文章

相关标签