热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

开发笔记:Java设计模式百例工厂方法模式

篇首语:本文由编程笔记#小编为大家整理,主要介绍了Java设计模式百例-工厂方法模式相关的知识,希望对你有一定的参考价值。本文源码见

篇首语:本文由编程笔记#小编为大家整理,主要介绍了Java设计模式百例 - 工厂方法模式相关的知识,希望对你有一定的参考价值。



本文源码见:https://github.com/get-set/get-designpatterns/tree/master/factory-method

工厂方法模式同简单工厂模式一样,也是创建类模式,又叫做虚拟构造(Virtual Constructor)模式或多态工厂(Polymorphic Factory)模式。其用意是定义一个创建产品对象的工厂接口,将实际创建工作推迟到子类中。

上篇说到,简单工厂模式并未做到完全的“开闭原则”。回顾一下,“开”即对扩展开放,这点是没错的,简单工厂模式的初衷之一就是方便增加“产品类型”的时候;“闭”即对修改关闭,这点其实并未做到,当需要增删改“产品类型”的时候,工厂类必须要修改,因为工厂类“知道”如何创建所有的产品类型的对象。

那么工厂方法模式就是为了完全满足“开闭原则”,即在简单工厂模式的基础上,做到当增加产品类型的时候,无需改动现有的代码。继续用上篇的例子:

例子

仍然是做一个画图软件,可以画矩形、三角形和圆形等,每一种图形都用一个类来管理: 
Rectangle 
Circle 
Triangle 
每个类都有各自的draw()方法,共同实现Shape接口。

Shape.java

public interface Shape {
   void draw();
}

Rectangle.java

public class Rectangle implements Shape {
   @Override
   public void draw() {
      System.out.println("Draw a rectangle.");
   }
}

Triangle.java

public class Triangle implements Shape {
   @Override
   public void draw() {
      System.out.println("Draw a triangle.");
   }
}

Circle.java

public class Circle implements Shape {
   @Override
   public void draw() {
      System.out.println("Draw a circle.");
   }
}

以上几个类都没有变化,有变化的是工厂类,工厂类也采用基于接口的设计,由不同的具体工厂类负责相应对象的创建:

ShapeFactory.java

public interface ShapeFactory {
    Shape getShape();
}

RectangleFactory.java

public class RectangleFactory implements ShapeFactory {
    public Shape getShape() {
        return new Rectangle();
    }
}

CircleFactory.java

public class CircleFactory implements ShapeFactory{
    public Shape getShape() {
        return new Circle();
    }
}

Triangle.Factory.java

public class CircleFactory implements ShapeFactory{
    public Shape getShape() {
        return new Circle();
    }
}

那么在需要某个形状的时候,就通过相应的具体工厂类创建即可:

Client.java

public class Client {
    public static void main(String[] args) {
        ShapeFactory factory = new CircleFactory();
        Shape c = factory.getShape();
        c.draw();
    }
}

再来看一下类图:

技术分享

与简单工厂模式对比以下:

技术分享

区别就在于简单工厂模式下的一个具体的工厂类转换成了基于接口ShapeFactory的三个具体工厂类。

好处也是明显的:当增加一个新的形状类型的时候,不需要对现有代码做任何更改,增加一个相应的实现了ShapeFactory的具体工厂类即可。可见,工厂方法模式能够完全做到“开闭原则”。

这个例子仍然是不恰当的,因为无论如何这一套模式设计比原始的实现方式有更加复杂了。所以再次赘述一遍注意事项,以上例子是为了说明工厂方法模式,但并不是一个合理的应用。复杂对象适合使用工厂模式,而简单对象,特别是只需要通过 new 就可以完成创建的对象,无需使用工厂模式。如果使用工厂模式,就需要引入一个工厂类,会增加系统的复杂度。

Java中的应用

下边看一下合理的应用场景是如何的,在Java中的实际应用的例子(来自《Java与模式》):

* 1. Java聚集中的应用 *

Java聚集是一套设计精良的数据结构实现,主要的Java聚集都实现自java.util.Collection接口,这个接口的父接口Iterable规定所有的Java聚集都必须提供一个iterator()方法,返还一个Iterator类型的对象:

java.lang.Iterable.java

public interface Iterable {
    ... ...
    Iterator iterator();
    ... ...
}

ArrayLis是我们常用的一个Collection实现类,其iterator()方法实现如下:

java.util.ArrayList.java

public class ArrayList extends AbstractList
        implements List, RandomAccess, Cloneable, java.io.Serializable {
    ... ...
    // 实现iterato接口,返回一个Iterator对象
    public Iterator iterator() {
        return new Itr();
    }
    private class Itr implements Iterator {
    ... ...
    }
    ... ...
}

可见,ArrayList类的iterator()方法就是一个具体工厂类的工厂方法,而Collection就是一个抽象工厂。除了ArrayList还有LinkedList等等具体实现类。

总结

从上边的例子可以看到,工厂方法模式其实是将“面向接口”编程的思路应用在了工厂类上,这样有几个方便的地方:

  1. 做到了完全的“开闭原则”,因为增加新的“产品”和相应的“工厂”均不需修改现有代码;

  2. 工厂设计模式通常应用在复杂的对象创建场景中,因此面临多层的继承关系,比如ArrayList实现了List接口,而后者继承自Collect接口,Collect又继承自Iterator接口。有时候具体工厂方法与具体产品是有层次对应关系的,比如:

技术分享

这种情况也是只有一个工厂类的简单工厂模式所无法满足的。



推荐阅读
  • Java容器中的compareto方法排序原理解析
    本文从源码解析Java容器中的compareto方法的排序原理,讲解了在使用数组存储数据时的限制以及存储效率的问题。同时提到了Redis的五大数据结构和list、set等知识点,回忆了作者大学时代的Java学习经历。文章以作者做的思维导图作为目录,展示了整个讲解过程。 ... [详细]
  • 本文详细介绍了Java中vector的使用方法和相关知识,包括vector类的功能、构造方法和使用注意事项。通过使用vector类,可以方便地实现动态数组的功能,并且可以随意插入不同类型的对象,进行查找、插入和删除操作。这篇文章对于需要频繁进行查找、插入和删除操作的情况下,使用vector类是一个很好的选择。 ... [详细]
  • 微软头条实习生分享深度学习自学指南
    本文介绍了一位微软头条实习生自学深度学习的经验分享,包括学习资源推荐、重要基础知识的学习要点等。作者强调了学好Python和数学基础的重要性,并提供了一些建议。 ... [详细]
  • Java太阳系小游戏分析和源码详解
    本文介绍了一个基于Java的太阳系小游戏的分析和源码详解。通过对面向对象的知识的学习和实践,作者实现了太阳系各行星绕太阳转的效果。文章详细介绍了游戏的设计思路和源码结构,包括工具类、常量、图片加载、面板等。通过这个小游戏的制作,读者可以巩固和应用所学的知识,如类的继承、方法的重载与重写、多态和封装等。 ... [详细]
  • Iamtryingtomakeaclassthatwillreadatextfileofnamesintoanarray,thenreturnthatarra ... [详细]
  • 本文介绍了一个Java猜拳小游戏的代码,通过使用Scanner类获取用户输入的拳的数字,并随机生成计算机的拳,然后判断胜负。该游戏可以选择剪刀、石头、布三种拳,通过比较两者的拳来决定胜负。 ... [详细]
  • 本文讨论了如何优化解决hdu 1003 java题目的动态规划方法,通过分析加法规则和最大和的性质,提出了一种优化的思路。具体方法是,当从1加到n为负时,即sum(1,n)sum(n,s),可以继续加法计算。同时,还考虑了两种特殊情况:都是负数的情况和有0的情况。最后,通过使用Scanner类来获取输入数据。 ... [详细]
  • 阿,里,云,物,联网,net,core,客户端,czgl,aliiotclient, ... [详细]
  • 本文介绍了如何在给定的有序字符序列中插入新字符,并保持序列的有序性。通过示例代码演示了插入过程,以及插入后的字符序列。 ... [详细]
  • 知识图谱——机器大脑中的知识库
    本文介绍了知识图谱在机器大脑中的应用,以及搜索引擎在知识图谱方面的发展。以谷歌知识图谱为例,说明了知识图谱的智能化特点。通过搜索引擎用户可以获取更加智能化的答案,如搜索关键词"Marie Curie",会得到居里夫人的详细信息以及与之相关的历史人物。知识图谱的出现引起了搜索引擎行业的变革,不仅美国的微软必应,中国的百度、搜狗等搜索引擎公司也纷纷推出了自己的知识图谱。 ... [详细]
  • JavaSE笔试题-接口、抽象类、多态等问题解答
    本文解答了JavaSE笔试题中关于接口、抽象类、多态等问题。包括Math类的取整数方法、接口是否可继承、抽象类是否可实现接口、抽象类是否可继承具体类、抽象类中是否可以有静态main方法等问题。同时介绍了面向对象的特征,以及Java中实现多态的机制。 ... [详细]
  • 本文讨论了一个关于cuowu类的问题,作者在使用cuowu类时遇到了错误提示和使用AdjustmentListener的问题。文章提供了16个解决方案,并给出了两个可能导致错误的原因。 ... [详细]
  • 本文介绍了Java高并发程序设计中线程安全的概念与synchronized关键字的使用。通过一个计数器的例子,演示了多线程同时对变量进行累加操作时可能出现的问题。最终值会小于预期的原因是因为两个线程同时对变量进行写入时,其中一个线程的结果会覆盖另一个线程的结果。为了解决这个问题,可以使用synchronized关键字来保证线程安全。 ... [详细]
  • CF:3D City Model(小思维)问题解析和代码实现
    本文通过解析CF:3D City Model问题,介绍了问题的背景和要求,并给出了相应的代码实现。该问题涉及到在一个矩形的网格上建造城市的情景,每个网格单元可以作为建筑的基础,建筑由多个立方体叠加而成。文章详细讲解了问题的解决思路,并给出了相应的代码实现供读者参考。 ... [详细]
  • [大整数乘法] java代码实现
    本文介绍了使用java代码实现大整数乘法的过程,同时也涉及到大整数加法和大整数减法的计算方法。通过分治算法来提高计算效率,并对算法的时间复杂度进行了研究。详细代码实现请参考文章链接。 ... [详细]
author-avatar
晨曦--雨荷
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有