研磨设计模式之简单工厂模式(场景问题)

2019-03-28 12:34|来源: 网络

   简单工厂不是一个标准的设计模式,但是它实在是太常用了,简单而又神奇,所以还是需要好好掌握的,就当是对学习设计模式的热身运动吧。
   为了保持一致性,我们尽量按照学习其它模式的步骤来进行学习。


1  场景问题

       大家都知道,在Java应用开发中,要“面向接口编程”。
       那么什么是接口?接口有什么作用?接口如何使用?一起来回顾一下:


1.1  接口回顾

(1)Java中接口的概念
       在Java中接口是一种特殊的抽象类,跟一般的抽象类相比,接口里面的所有方法都是抽象方法,接口里面的所有属性都是常量。也就是说,接口里面是只有方法定义而不会有任何方法实现。
(2)接口用来干什么
       通常用接口来定义实现类的外观,也就是实现类的行为定义,用来约束实现类的行为。接口就相当于一份契约,根据外部应用需要的功能,约定了实现类应该要实现的功能,但是具体的实现类除了实现接口约定的功能外,还可以根据需要实现一些其它的功能,这是允许的,也就是说实现类的功能包含但不仅限于接口约束的功能。
       通过使用接口,可以实现不相关类的相同行为,而不需考虑这些类之间的层次关系,接口就是实现类对外的外观。
(3)接口的思想
       根据接口的作用和用途,浓缩下来,接口的思想就是“封装隔离”。
       通常提到封装是指对数据的封装,但是这里的封装是指“对被隔离体的行为的封装”,或者是“对被隔离体的职责的封装”;而隔离指的是外部调用和内部实现,外部调用只能通过接口进行调用,而外部调用是不知道内部具体实现的,也就是说外部调用和内部实现是被接口隔离开的。
(4)使用接口的好处
       由于外部调用和内部实现被接口隔离开了,那么只要接口不变,内部实现的变化就不会影响到外部应用,从而使得系统更灵活,具有更好的扩展性和可维护性,这也就是所谓“接口是系统可插拔性的保证”这句话的意思。
(5)接口和抽象类的选择
       既然接口是一种特殊的抽象类,那么在开发中,何时选用接口,何时选用抽象类呢?
       对于它们的选择,在开发中是一个很重要的问题,特别总结两句话给大家:

  • 优先选用接口

  • 在如下情况应选择抽象类:既要定义子类的行为,又要为子类提供公共的功能

1.2  面向接口编程

       面向接口编程是Java编程中的一个重要原则。
       在Java 程序设计里面,非常讲究层的划分和模块的划分。通常按照三层来划分Java程序,分别是表现层、逻辑层、数据层,它们之间都要通过接口来通讯。
       在每一个层里面,又有很多个小模块,一个小模块对外也应该是一个整体,那么一个模块对外也应该提供接口,其它地方需要使用到这个模块的功能,都应该通过此接口来进行调用。这也就是常说的“接口是被其隔离部分的外观”。基本的三层结构如图1所示:


图1  基本的三层结构示意图


在一个层内部的各个模块交互也要通过接口,如图2所示:


图2  一个层内部的各个模块交互示意图


       各个部分的接口具体应该如何去定义,具体的内容是什么,不去深究,那是需要具体问题具体分析的,这里只是来学习设计的方法。
       上面频频提到“组件”,那么什么是组件呢?先简单的名词解释一下:
       所谓组件:从设计上讲,组件就是能完成一定功能的封装体。小到一个类,大到一个系统,都可以称为组件,因为一个小系统放到更大的系统里面去,也就当个组件而已。事实上,从设计的角度看,系统、子系统、模块、组件等说的其实是同一回事情,都是完成一定功能的封装体,只不过功能多少不同而已。
       继续刚才的思路,大家会发现,不管是一层还是一个模块或者一个组件,都是一个被接口隔离的整体,那么下面我们就不去区分它们,统一认为都是接口隔离体即可,如图3所示:



图3  接口隔离体示意图


既然在Java中需要面向接口编程,那么在程序中到底如何使用接口,来做到真正的面向接口编程呢?

1.3  不用模式的解决方案

       回忆一下,以前是如何使用接口的呢,假设有一个接口叫Api,然后有一个实现类Impl实现了它,在客户端怎么用这个接口呢?
       通常都是在客户端创建一个Impl的实例,把它赋值给一个Api接口类型的变量,然后客户端就可以通过这个变量来操作接口的功能了,此时具体的结构图如图4:


图4  基本的接口和实现

还是用代码来说明,会更清楚一些。

(1)先定义接口Api,示例代码如下:

Java代码
  1. /**

  2. * 某个接口(通用的、抽象的、非具体的功能)

  3. */  

  4. public interface Api {  

  5.    /**

  6.     * 某个具体的功能方法的定义,用test1来演示一下。

  7.     * 这里的功能很简单,把传入的s打印输出即可

  8.     * @param s 任意想要打印输出的字符串

  9.     */  

  10.    public void test1(String s);  

  11. }  


(2)既然有了接口,自然就要有实现,定义实现Impl,示例代码如下:

Java代码
  1. /**

  2. * 对接口的实现

  3. */  

  4. public class Impl implements Api{  

  5.    public void test1(String s) {  

  6.        System.out.println("Now In Impl. The input s=="+s);  

  7.    }  

  8. }  

(3)那么此时的客户端怎么写呢?
按照Java的知识,接口不能直接使用,需要使用接口的实现类,示例代码如下:

Java代码
  1. /**

  2. * 客户端:测试使用Api接口

  3. */  

  4. public class Client {  

  5.    public static void main(String[] args) {  

  6.        Api api = new Impl();  

  7.        api.test1("哈哈,不要紧张,只是个测试而已!");  

  8.    }  

  9. }  

1.4  有何问题

       上面写得没错吧,在Java的基础知识里面就是这么学的,难道这有什么问题吗?
       请仔细看位于客户端的下面这句话:

Java代码
  1. Api api = new Impl();  

       然后再想想接口的功能和思想,发现什么了?仔细再想想?

       你会发现在客户端调用的时候,客户端不但知道了接口,同时还知道了具体的实现就是Impl。而接口的思想是“封装隔离”,而Impl这个实现类,应该是被接口Api封装并同客户端隔离开的,也就是说,客户端根本就不应该知道具体的实现类是Impl。
       有朋友说,那好,我就把Impl从客户端拿掉,让Api真正的对实现进行“封装隔离”,然后我们还是面向接口来编程。可是,新的问题出现了,当他把“new Impl()”去掉过后,发现他无法得到Api接口对象了,怎么办呢?
       把这个问题描述一下:在Java编程中,出现只知接口而不知实现,该怎么办?
       就像现在的Client,它知道要使用Api接口,但是不知由谁实现,也不知道如何实现,从而得不到接口对象,就无法使用接口,该怎么办呢?


请看下节:解决方案


本文链接:研磨设计模式之简单工厂模式(场景问题),转自:http://chjavach.iteye.com/blog/800325

相关问答

更多
  • 这个问题很简单啊,就是一个接口,N个具体类,然后创建一个抽象工厂根据传入的类名生成不同的处理类。首先看看工程结构图: Common接口: package pkg1.pkg2; /** * Common计算接口 * * @author * */ public interface Common { // 接口方法返回结算结果 public long calulate(int a, int b, int c); } package pkg1; import pkg1.pkg2.Common; /** * Car0 ...
  • 在不需要用对象成员的时候就用类成员,这个没什么好说的... 一定要说的话静态方法调用速度快
  • Singleton--单态模式 vo--值对象 DAO MVC 工厂模式 常用的吧
  • 工厂模式是最常用的实例化对象模式了,是用工厂方法代替new操作的一种模式。   著名的Jive论坛 ,就大量使用了工厂模式,工厂模式在Java程序系统可以说是随处可见。因为工厂模式就相当于创建实例对象的new,经常要根据类Class生成实例对象,如A a=new A() 工厂模式也是用来创建实例对象的,所以以后new时就要多个心眼,是否可以考虑使用工厂模式,虽然这样做,可能多做一些工作,但会给系统带来更大的可扩展性和尽量少的修改量。
  • 一共23种设计模式! 引用《软件秘笈-设计模式那点事》书籍: 按照目的来分,设计模式可以分为创建型模式、结构型模式和行为型模式。 创建型模式用来处理对象的创建过程;结构型模式用来处理类或者对象的组合;行为型模式用来对类或对象怎样交互和怎样分配职责进行描述。 创建型模式用来处理对象的创建过程,主要包含以下5种设计模式:  工厂方法模式(Factory Method Pattern)  抽象工厂模式(Abstract Factory Pattern)  建造者模式(Builder Pattern)  原 ...
  • 简单工作设计模式就是把三层结构分成多层,包括数据工厂等,达到设计分层的目的而序列化及反序列化只是对数据进行物理存储和读取的一种方式.
  • 工厂是指生产实例的地方。那就简单一个,直接命名为createInstance()。此方法通常是静态的,而且还会带有参数和返回值。举个例子:例如牛、羊、马、狗都继承动物类,那createInstance()的返回值应该为 动物(因为工厂就是生产动物的嘛,所以返回值也应该为动物),参数应该为动物名称(这样工厂根据名称才知道你要生产哪种动物啊)。这样就可以根据传入的的动物名称,产生一个动物实例。createInstance的实现:switch(动物名称) case 牛:return new 牛();case 羊: ...
  • 都是设计模式,mvc是一种复合的模式,工厂是基本
  • 工厂是用来造东西的 而你造出来的对象类型是 Namer 所以 Namer nm这样声明(getName(txtName.Text); 这个方法的返回值类型是Namer) nameFact.getName(txtName.Text); 这句话结合你上面的来看 只能是你上面写错了吧 Namer nm =nameFact.getName(txtName.Text); 这句话应该是声明一个姓名对象 用来接收工厂类制造姓名的方法所返回的值 并且你之前的 getName(txtName.Text); 应该是个静态方法 ...
  • 简单工厂模式(Simple Factory Pattern),又称静态工厂模式(Static Factory Pattern)。举两个例子以快速明白Java中的简单工厂模式: 女娲抟土造人 话说:“天地开辟,未有人民,女娲抟土为人。”女娲需要用土造出一个个的人,但在女娲造出人之前,人的概念只存在于女娲的思想里面。 女娲造人,这就是简单工厂模式的应用。   首先,在这个造人的思想里面,有几个重要的角色:女娲本身、抽象的人的概念和女娲所造出的一个个具体的人。   1.)女娲是一个工厂类,也就是简单工厂模式的核心 ...