研磨设计模式之工厂方法模式(Factory Method)-场景问题

2019-03-08 16:01|来源: 网络

1  场景问题

1.1  导出数据的应用框架

       考虑这样一个实际应用:实现一个导出数据的应用框架,来让客户选择数据的导出方式,并真正执行数据导出。
       在一些实际的企业应用中,一个公司的系统往往分散在很多个不同的地方运行,比如各个分公司或者是门市点,公司没有建立全公司专网的实力,但是又不愿意让业务数据实时的在广域网上传递,一个是考虑数据安全的问题,一个是运行速度的问题。
       这种系统通常会有一个折中的方案,那就是各个分公司内运行系统的时候是独立的,是在自己分公司的局域网内运行。然后在每天业务结束的时候,各个分公司会导出自己的业务数据,然后把业务数据打包通过网络传送给总公司,或是专人把数据送到总公司,然后由总公司进行数据导入和核算。
       通常这种系统,在导出数据上,会有一些约定的方式,比如导出成:文本格式、数据库备份形式、Excel格式、Xml格式等等。
       现在就来考虑实现这样一个应用框架。在继续之前,先来了解一些关于框架的知识。


1.2  框架的基础知识

(1):框架是什么
       简单点说:框架就是能完成一定功能的半成品软件
       就其本质而言,框架是一个软件,而且是一个半成品的软件。所谓半成品,就是还不能完全实现用户需要的功能,框架只是实现用户需要的功能的一部分,还需要进一步加工,才能成为一个满足用户需要的、完整的软件。因此框架级的软件,它的主要客户是开发人员,而不是最终用户。
       有些朋友会想,既然框架只是个半成品,那何必要去学习和使用框架呢?学习成本也不算小,那就是因为框架能完成一定的功能,也就是这“框架已经完成的一定的功能”在吸引着开发人员,让大家投入去学习和使用框架。


(2):框架能干什么
       能完成一定功能,加快应用开发进度
       由于框架完成了一定的功能,而且通常是一些基础的、有难度的、通用的功能,这就避免我们在应用开发的时候完全从头开始,而是在框架已有的功能之上继续开发,也就是说会复用框架的功能,从而加快应用的开发进度。
       给我们一个精良的程序架构
       框架定义了应用的整体结构,包括类和对象的分割,各部分的主要责任,类和对象怎么协作,以及控制流程等等。
现在Java界大多数流行的框架,大都出自大师手笔,设计都很精良。基于这样的框架来开发,一般会遵循框架已经规划好的结构来进行开发,从而让我们开发的应用程序的结构也相对变得精良了。


(3):对框架的理解
       基于框架来开发,事情还是那些事情,只是看谁做的问题
       对于应用程序和框架的关系,可以用一个图来简单描述一下,如图1所示:


图1  应用程序和框架的简单关系示意图

       如果没有框架,那么客户要求的所有功能都由开发人员自己来开发,没问题,同样可以实现用户要求的功能,只是开发人员的工作多点。
       如果有了框架,框架本身完成了一定的功能,那么框架已有的功能,开发人员就可以不做了,开发人员只需要完成框架没有的功能,最后同样是完成客户要求的所有功能,但是开发人员的工作就减少了。
       也就是说,基于框架来开发,软件要完成的功能并没有变化,还是客户要求的所有功能,也就是“事情还是那些事情”的意思。但是有了框架过后,框架完成了一部分功能,然后开发人员再完成一部分功能,最后由框架和开发人员合起来完成了整个软件的功能,也就是看这些功能“由谁做”的问题。

        基于框架开发,可以不去做框架所做的事情,但是应该明白框架在干什么,以及框架是如何实现相应功能的
       事实上,在实际开发中,应用程序和框架的关系,通常都不会如上面讲述的那样,分得那么清楚,更为普遍的是相互交互的,也就是应用程序做一部分工作,然后框架做一部分工作,然后应用程序再做一部分工作,然后框架再做一部分工作,如此交错,最后由应用程序和框架组合起来完成用户的功能要求。
       也用个图来说明,如图2所示:

图2  应用程序和框架的关系示意图


       如果把这个由应用程序和框架组合在一起构成的矩形,当作最后完成的软件。试想一下,如果你不懂框架在干什么的话,相当于框架对你来讲是个黑盒,也就是相当于在上面图2中,去掉框架的两块,会发现什么?没错,剩下的应用程序是支离破碎的,是相互分隔开来的。
       这会导致一个非常致命的问题,整个应用是如何运转起来的,你是不清楚的,也就是说对你而言,项目已经失控了,从项目管理的角度来讲,这是很危险的。
       因此,在基于框架开发的时候,虽然我们可以不去做框架所做的事情,但是应该搞明白框架在干什么,如果条件许可的话,还应该搞清楚框架是如何实现相应功能的,至少应该把大致的实现思路和实现步骤搞清楚,这样我们才能整体的掌控整个项目,才能尽量减少出现项目失控的情况。


(4):框架和设计模式的关系
       设计模式比框架更抽象
      框架已经是实现出来的软件了,虽然只是个半成品的软件,但毕竟是已经实现出来的了。而设计模式的重心还在于解决问题的方案上,也就是还停留在思想的层面。因此设计模式比框架更为抽象。
     

      设计模式是比框架更小的体系结构元素
      如上所述,框架是已经实现出来的软件,并实现了一系列的功能,因此一个框架,通常会包含多个设计模式的应用。

       框架比设计模式更加特例化
      框架是完成一定功能的半成品软件,也就是说,框架的目的很明确,就是要解决某一个领域的某些问题,那是很具体的功能,不同的领域实现出来的框架是不一样的。
     而设计模式还停留在思想的层面,在不同的领域都可以应用,只要相应的问题适合用某个设计模式来解决。因此框架总是针对特定领域的,而设计模式更加注重从思想上,从方法上来解决问题,更加通用化。

1.3  有何问题
      分析上面要实现的应用框架,不管用户选择什么样的导出格式,最后导出的都是一个文件,而且系统并不知道究竟要导出成为什么样的文件,因此应该有一个统一的接口,来描述系统最后生成的对象,并操作输出的文件。
      先把导出的文件对象的接口定义出来,示例代码如下:

/**

* 导出的文件对象的接口

*/

public interface ExportFileApi {

   /**

    * 导出内容成为文件

    * @param data 示意:需要保存的数据

    * @return 是否导出成功

    */

   public boolean export(String data);

}

       对于实现导出数据的业务功能对象,它应该根据需要来创建相应的ExportFileApi的实现对象,因为特定的ExportFileApi的实现是与具体的业务相关的。但是对于实现导出数据的业务功能对象而言,它并不知道应该创建哪一个ExportFileApi的实现对象,也不知道如何创建。
       也就是说:对于实现导出数据的业务功能对象,它需要创建ExportFileApi的具体实例对象,但是它只知道ExportFileApi接口,而不知道其具体的实现。那该怎么办呢?


本文链接:研磨设计模式之工厂方法模式(Factory Method)-场景问题,转自:http://chjavach.iteye.com/blog/692790

相关问答

更多
  • 这不是GOF创作模式。 它是抽象工厂模式的变体,有时称为参数化工厂模式 。 参数化工厂根据传递给create方法的参数(通常是Id或类型说明符)创建不同的对象。 你的例子中的GOF工厂方法就是这样的(只是一个例子......没有意义......) struct AreaCalculator { virtual double calculateArea() = 0; }; struct CircleCalculator { CircleCalculator(const Circle& cir ...
  • 两者之间的区别 “工厂方法”和“抽象工厂”的主要区别在于工厂方法是一种单一的方法,抽象工厂是一个对象。 我觉得很多人把这两个术语搞糊涂了,开始互换使用。 我记得我很难找到当我学到他们的时候有什么区别。 因为工厂方法只是一种方法,它可以在一个子类中被覆盖,所以你的报价的下半部分是: ... Factory Method模式使用继承并依赖于一个子类来处理所需的对象实例化。 引用假定一个对象在这里调用它自己的工厂方法。 因此,唯一可以改变返回值的东西将是一个子类。 抽象工厂是一个具有多种工厂方法的对象。 看你的报 ...
  • 最简单的方法是使用单个静态字段,并在已创建映射时返回该值。 代码未经测试,但我认为这个概念很简单: public class MapCreator{ private static Map theOnlyMap; public synchronized Map createMap(char mapType){ if( theOnlyMap != null ) return theOnlyMap; switch(mapType){ case ...
  • 我不确定工厂方法设计模式在函数式编程中的作用程度。 模式的目标是隐藏对象的创建,以便您可以仅使用对象的抽象表示。 当您以功能方式使用F#时,您将在大多数时间使用具体表示。 例如,这使您能够在滑板类型上进行模式匹配。 当然,F#允许您将功能风格与面向对象的风格相结合。 出于某些目的,OO风格在F#中运行良好。 在这种情况下,您的方法看起来很合理。 您的工厂方法可以采用具体类型(例如,区分联合)作为参数,而不是字符串。 然后工厂的任务是从具体表示构建抽象表示: // Abstract representatio ...
  • 工厂方法已修复 - 您无法在运行时更改它。 抽象工厂允许您使用不同工厂创建对象,这可以在运行时根据某些条件进行选择。 Button button = WinButtonFactory.create(); //will always be a "windows button" Button button = buttonFactory.create(); 像这样的第二个可以是WinButtonFactory extends ButtonFactory或者MacOSXButtonFactory extends ...
  • 为什么不把工厂组成为Creator类而不是用抽象方法表达它呢? 因为在这种情况下,客户端“知道”要实例化哪个Factory类,这会破坏模式的整体目的。 整个想法是,客户不知道什么是工厂,它只是调用一个Abstract类。 假设你将一些第三方工厂提供者插入到你的框架中,并且只要达到目的,你就不知道他们实例化了什么(也不关心)。 Why not composing the Factory into the Creator class instead of expressing it using an abstr ...
  • 我知道工厂方法模式有更多我缺少的东西但是依靠继承的优势组合,我找到了以下方法,在同一场景中解决同样的问题 使用Factory Method模式而不是普通旧组合时,您可以获得以下几个优点: 1.关注点分离和开放原则 :为每个相关的对象组创建一个工厂子类。 此工厂子类仅负责创建属于特定组的那些产品。 ABCProductFactory只关注创建ABCProduct1 , ABCProduct2等CDEProductFactory只关注创建CDEProduct1 , CDEProduct2等。 对于每个新产品组, ...
  • 遗憾的是,您正在阅读的链接并未提供该模式的实际示例。 实际上,根据原始的GoF设计模式,这种模式称为抽象工厂 (工厂方法是一种不同的模式)。 当您拥有可以创建一系列对象的工厂时,将使用抽象工厂模式。 例如,你可以拥有和AbstractGUIFactory ,它可以有方法createButton(), createWindow(), createTitleBar等。然后,你将拥有像WindowsGUIFactory, MacGUIFactory, MotifGUIFactory等具体的工厂,每个工厂都会产生B ...
  • 抽象工厂模式将产品对象的创建推迟到ConcreteFactory子类。 由于客户端期望Factory类(它是ConcreteFactory子类的父类)作为方法参数; 基于ConcreteFactory传递的实例,创建相应的产品实例。 因此,Abstract Factory通过在运行时传递的ConcreteFactory实例上调用工厂方法来创建产品实例。 因此,这是对象设计模式。 通常这些混凝土工厂是单身人士。 然而,工厂方法发生在班级。 必须创建一个新的ConcreteFactory类来实例化Concret ...
  • 工厂的基本思想是函数返回从已知基类派生的堆分配对象。 因此,在你的情况下,你可能会在你的主应用程序中有一些代码调用dll中的工厂,找回未知动态类型和实现的对象,但你会知道它满足特定基类的API要求。 然后通过该接口使用该对象,并通过其大概的虚拟析构函数将其删除。 取决于实际派生类的选择方式,工厂方法有多种类型,但通常它会检查函数的一些输入,IO流或XML结构等,并计算出适当的类型。 工厂是否在dll中对这里的整体模型没有什么影响,但它确实可以更容易地更新派生对象的列表和实现,而无需重新编译应用程序。 有关更 ...