`

设计模式——简单工厂模式

阅读更多

 

Java简单工厂

简单工厂不是一个标准的设计模式,但是它实在是太常用了,简单而又神奇,所以还是需要好好掌握的,就当是对学习设计模式的热身运动吧。

为了保持一致性,我们尽量按照学习其它模式的步骤来进行学习。

场景问题

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

1.1  接口回顾

1Java中接口的概念

Java中接口是一种特殊的抽象类,跟一般的抽象类相比,接口里面的所有方法都是抽象方法,接口里面的所有属性都是常量。也就是说,接口里面是只有方法定义而不会有任何方法实现。

2)接口用来干什么

通常用接口来定义实现类的外观,也就是实现类的行为定义,用来约束实现类的行为。接口就相当于一份契约,根据外部应用需要的功能,约定了实现类应该要实现的功能,但是具体的实现类除了实现接口约定的功能外,还可以根据需要实现一些其它的功能,这是允许的,也就是说实现类的功能包含但不仅限于接口约束的功能。

通过使用接口,可以实现不相关类的相同行为,而不需考虑这些类之间的层次关系,接口就是实现类对外的外观。

3)接口的思想

根据接口的作用和用途,浓缩下来,接口的思想就是封装隔离

通常提到封装是指对数据的封装,但是这里的封装是指对被隔离体的行为的封装,或者是对被隔离体的职责的封装;而隔离指的是外部调用和内部实现,外部调用只能通过接口进行调用,而外部调用是不知道内部具体实现的,也就是说外部调用和内部实现是被接口隔离开的。

4)使用接口的好处

由于外部调用和内部实现被接口隔离开了,那么只要接口不变,内部实现的变化就不会影响到外部应用,从而使得系统更灵活,具有更好的扩展性和可维护性,这也就是所谓接口是系统可插拔性的保证这句话的意思。

5)接口和抽象类的选择

既然接口是一种特殊的抽象类,那么在开发中,何时选用接口,何时选用抽象类呢?

对于它们的选择,在开发中是一个很重要的问题,特别总结两句话给大家:

            优先选用接口

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

1.2  面向接口编程

面向接口编程是Java编程中的一个重要原则

      Java 程序设计里面,非常讲究层的划分和模块的划分。通常按照三层来划分Java程序,分别是表现层、逻辑层、数据层,它们之间都要通过接口来通讯。

在每一个层里面,又有很多个小模块,一个小模块对外也应该是一个整体,那么一个模块对外也应该提供接口,其它地方需要使用到这个模块的功能,都应该通过此接口来进行调用。这也就是常说的接口是被其隔离部分的外观。基本的三层结构如图1所示:

 


 

基本的三层结构示意图

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

 


 

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

各个部分的接口具体应该如何去定义,具体的内容是什么,不去深究,那是需要具体问题具体分析的,这里只是来学习设计的方法。

上面频频提到组件,那么什么是组件呢?先简单的名词解释一下:

所谓组件:从设计上讲,组件就是能完成一定功能的封装体。小到一个类,大到一个系统,都可以称为组件,因为一个小系统放到更大的系统里面去,也就当个组件而已。事实上,从设计的角度看,系统、子系统、模块、组件等说的其实是同一回事情,都是完成一定功能的封装体,只不过功能多少不同而已。

继续刚才的思路,大家会发现,不管是一层还是一个模块或者一个组件,都是一个被接口隔离的整体,那么下面我们就不去区分它们,统一认为都是接口隔离体即可,如图3所示:



 
接口隔离体示意图

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

1.3  不用模式的解决方案

回忆一下,以前是如何使用接口的呢,假设有一个接口叫Api,然后有一个实现类Impl实现了它,在客户端怎么用这个接口呢?

通常都是在客户端创建一个Impl的实例,把它赋值给一个Api接口类型的变量,然后客户端就可以通过这个变量来操作接口的功能了,此时具体的结构图如图4

 


基本的接口和实现

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

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

 

/**
* 某个接口(通用的、抽象的、非具体的功能) 
*/
public interface Api {
    /**
     * 某个具体的功能方法的定义,用test1来演示一下。
     * 这里的功能很简单,把传入的s打印输出即可 
     * @param s 任意想要打印输出的字符串
     */
    public void test1(String s);
}
 

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

 

/**
* 对接口的实现 
*/
public class Impl implements Api{
    public void test1(String s) {
        System.out.println("Now In Impl. The input s=="+s);
    }
}
 

 3)那么此时的客户端怎么写呢?

按照Java的知识,接口不能直接使用,需要使用接口的实现类,示例代码如下:

 

/**
* 客户端:测试使用Api接口
*/
public class Client {
    public static void main(String[] args) {
        Api api = new Impl();
        api.test1("哈哈,不要紧张,只是个测试而已!");
    }
} 
 

1.4  有何问题

上面写得没错吧,在Java的基础知识里面就是这么学的,难道这有什么问题吗?

请仔细看位于客户端的下面这句话:

        Api api = new Impl();

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

      你会发现在客户端调用的时候,客户端不但知道了接口,同时还知道了具体的实现就是Impl。而接口的思想是封装隔离,而Impl这个实现类,应该是被接口Api封装并同客户端隔离开的,也就是说,客户端根本就不应该知道具体的实现类是Impl

有朋友说,那好,我就把Impl从客户端拿掉,让Api真正的对实现进行封装隔离,然后我们还是面向接口来编程。可是,新的问题出现了,当他把“new Impl()”去掉过后,发现他无法得到Api接口对象了,怎么办呢?

把这个问题描述一下:Java编程中,出现只知接口而不知实现,该怎么办?

就像现在的Client,它知道要使用Api接口,但是不知由谁实现,也不知道如何实现,从而得不到接口对象,就无法使用接口,该怎么办呢?

 

解决方案

简单工厂来解决

      用来解决上述问题的一个合理的解决方案就是简单工厂,那么什么是简单工厂呢?

1:简单工厂定义



2:应用简单工厂来解决的思路

分析上面的问题,虽然不能让模块外部知道模块内的具体实现,但是模块内部是可以知道实现类的,而且创建接口是需要具体实现类的。

那么干脆在模块内部新建一个类,在这个类里面来创建接口,然后把创建好的接口返回给客户端,这样外部应用就只需要根据这个类来获取相应的接口对象,然后就可以操作接口定义的方法了。把这样的对象称为简单工厂,就叫Factory吧。

这样一来,客户端就可以通过这个Factory来获取需要的接口对象,然后调用接口的方法来实现需要的功能,而且客户端也不用再关心具体实现了。

2.2  简单工厂结构和说明

简单工厂的结构如图5所示:

 

 
 Api
       
定义客户所需要的功能接口
Impl
      
具体实现Api的实现类,可能会有多个
Factory
       工厂,选择合适的实现类来创建Api接口对象
Client
      
客户端,通过Factory去获取Api接口对象,然后面向Api接口编程

2.3  简单工厂示例代码

1)先看看Api的定义,示例代码如下:

 

/**
 * 接口的定义,该接口可以通过简单工厂来创建
 */
public interface Api {
    /**
     * 示意,具体的功能方法的定义
     * @param s 示意,需要的参数
     */
    public void operation(String s);
}
 

 2)定义了接口,该来实现它了,ImplA的示例代码如下:

 

/**
 * 接口的具体实现对象A 
 */
public class ImplA implements Api{
    public void operation(String s) {
        //实现功能的代码,示意一下
        System.out.println("ImplA s=="+s);
    }
}
 

ImplB的示意实现和ImplA基本一样,示例代码如下:

 

/**
 * 接口的具体实现对象B 
 */
public class ImplB implements Api{
    public void operation(String s) {
        //实现功能的代码,示意一下
        System.out.println("ImplB s=="+s);
    }
}
 

3)该来看看简单工厂的实现,示例代码如下:

 

/** 
 * 工厂类,用来创造Api对象 
 */
public class Factory { 
    /** 
     * 具体的创造Api对象的方法 
     * @param condition 示意,从外部传入的选择条件 
     * @return 创造好的Api对象 
     */
    public static Api createApi(int condition){ 
        //应该根据某些条件去选择究竟创建哪一个具体的实现对象, 
        //这些条件可以从外部传入,也可以从其它途径获取。 
        //如果只有一个实现,可以省略条件,因为没有选择的必要。 
       //示意使用条件 
        Api api = null; 
        if(condition == 1){ 
            api = new ImplA(); 
        }else if(condition == 2){ 
            api = new ImplB(); 
        } 
        return api; 
    } 
}
 

 4)再来看看客户端的示意,示例代码如下:

/**
 * 客户端,使用Api接口
 */
public class Client {
    public static void main(String[] args) {
        //通过简单工厂来获取接口对象
        Api api = Factory.createApi(1);
        api.operation("正在使用简单工厂");
    }
}

 

2.4  使用简单工厂重写示例 

      要使用简单工厂来重写前面的示例,主要就是要创建一个简单工厂对象,让简单工厂来负责创建接口对象。然后让客户端通过工厂来获取接口对象,而不再由客户端自己去创建接口的对象了。

此时系统的结构如图6所示。

 


 

使用简单工厂重写示例的结构示意图

1)接口Api和实现类Impl都和前面的示例一样,就不去赘述了。

2)新创建一个简单工厂的对象,示例代码如下:

 

/**
 * 工厂类,用来创造Api对象
 */
public class Factory {
    /**
     * 具体的创造Api对象的方法
     * @return 创造好的Api对象
     */
    public static Api createApi(){
        //由于只有一个实现,就不用条件判断了
        return new Impl();
    }
}
 

 3)使用简单工厂

 客户端如何使用简单工厂提供的功能呢?这个时候,客户端就不用再自己去创建接口的对象了,应该使用工厂来获取,经过改造,客户端代码如下: 

/** 
* 客户端:测试使用Api接口 
*/
public class Client { 
    public static void main(String[] args) { 
        //重要改变,没有new Impl()了,取而代之Factory.createApi() 
        Api api = Factory.createApi(); 
        api.test1("哈哈,不要紧张,只是个测试而已!"); 
    } 
} 

 

就如同上面的示例,客户端通过简单工厂创建了一个实现接口的对象,然后面向接口编程,从客户端来看,它根本就不知道具体的实现是什么,也不知道是如何实现的,它只知道通过工厂获得了一个接口对象,然后就能通过这个接口来获取想要的功能。

事实上,简单工厂能帮助我们真正开始面向接口编程,像以前的做法,其实只是用到了接口的多态那部分的功能,最重要的封装隔离性并没有体现出来。

  • 大小: 5 KB
  • 大小: 3.3 KB
  • 大小: 1.5 KB
  • 大小: 4.2 KB
  • 大小: 1.9 KB
  • 大小: 34.8 KB
  • 大小: 4.7 KB
分享到:
评论

相关推荐

    实验二 简单工厂模式.zip_31QS_C#_设计模式——简单工厂模式_设计模式实验

    简单工厂模式是软件设计模式中的一种基础模式,它属于创建型模式,主要解决对象的创建问题,降低了客户端代码与具体产品类之间的耦合度。在本实验中,我们将深入理解和应用C#语言实现简单工厂模式。 简单工厂模式的...

    设计模式——简单工厂 VS 工厂方法

    简单工厂模式,也称为静态工厂模式,是一种创建型设计模式,它提供了一个静态方法来创建对象,而无需暴露实例化逻辑。在简单工厂模式中,一个单一的工厂类负责生产所有相关类型的实例。这种模式适用于产品种类较少且...

    设计模式——抽象工厂模式

    抽象工厂模式是设计模式中的一种创建型模式,它提供了一种创建对象集合的接口,而无需指定具体类。这种模式的主要目的是为了隔离产品对象的创建和使用,使得系统对产品类的依赖降低到最低,同时也方便了产品的扩展和...

    软件设计模式——抽象工厂

    抽象工厂模式是一种重要的软件设计模式,它属于创建型模式,主要解决的是当系统需要创建一系列相关或相互依赖的对象时,而这些对象的类在运行时可能不确定的问题。在这个模式中,我们通过一个抽象工厂接口来定义创建...

    Android之大话设计模式——:抽象工厂模式借鉴.pdf

    Android之大话设计模式——:抽象工厂模式借鉴.pdf

    c#工厂模式——简单工厂,抽象工厂,单件模式实例

    在软件设计模式中,工厂模式是一种非常常见的创建型模式,它提供了一种创建对象的最佳方式。C#中的工厂模式分为简单工厂、抽象工厂和单例模式三种,每一种都有其特定的应用场景和优势。 1. **简单工厂模式**: ...

    设计模式——工厂模式在开发中的应用(简单计算器)

    这个是http://blog.csdn.net/dawanganban/article/details/9884681博客中java设计模式的源代码。下载前请先看《设计模式——工厂模式在开发中的应用》一文。

    设计模式——工厂方法模式

    工厂方法模式是面向对象设计模式中的一种,它属于创建型模式,主要解决的是当系统需要创建的对象具有多种类型,而具体创建哪种类型的对象在运行时才能确定的问题。在这个压缩包中,`FactoryMethod`可能包含了Java...

    c#工厂模式——简单工厂_抽象工厂实例

    ### C#工厂模式详解——简单工厂与抽象工厂实例解析 #### 一、工厂模式概述 工厂模式是一种常用的设计模式,在面向对象编程中被广泛应用于创建对象。它通过提供一个统一的接口来创建一系列相关的或相互依赖的对象...

    Android之大话设计模式——:抽象工厂模式参考.pdf

    Android之大话设计模式——:抽象工厂模式参考.pdf

    设计模式C#描述之——简单工厂模式

    ### 设计模式C#描述之——简单工厂模式 #### 知识点概述 简单工厂模式是一种常用的设计模式,属于创建型模式之一。该模式的主要目的是为了封装产品对象的创建过程,将这一过程从客户端分离出来,使客户端无须关心...

    设计模式(简单工厂和工厂方法C++版)Demo程序

    本Demo程序主要涵盖了两种常用的创建型设计模式——简单工厂模式(Simple Factory)和工厂方法模式(Factory Method)。这两种模式都是用来创建对象,但它们在灵活性和抽象程度上有所不同。 简单工厂模式是一种静态...

    设计模式——刘伟

    设计模式是软件工程中的一种重要概念,它代表了在特定情境下解决常见问题的最佳实践。刘伟先生在讲解设计模式时,通常会深入浅出地介绍这些模式的原理、应用场景以及如何有效地在实际编程中应用它们。设计模式并不是...

    设计模式——GFour

    《设计模式——GFour》是一本深受IT从业者喜爱的经典书籍,尤其在C++开发者中具有广泛影响力。设计模式是软件工程领域中的一种最佳实践,它总结了在特定情境下解决问题的常见方法,使得代码可读性更强,复用性更高,...

    设计模式——基于C#的工程化实现及扩展

    ### 设计模式——基于C#的工程化实现及扩展 #### 概述 本书旨在向读者展示如何利用C# 2.0语法有效地实现和应用设计模式,使其不仅仅局限于简单的例子,而是能够在实际工程项目中发挥重要作用。全书分为七个部分,...

    设计模式——原版的设计模式

    设计模式是一种在软件设计中被广泛认可的解决特定问题、经过良好记录并可重用的解决方案。它们代表了在各种编程环境中反复出现的问题的最佳实践。原版的设计模式通常指的是最初由“Gang of Four”(GoF)在他们的...

    设计模式实现——抽象工厂模式结构实现

    抽象工厂模式是设计模式中的一种创建型模式,它提供了一种创建对象集合的接口,而无需指定具体的类。这种模式允许客户端使用一个通用接口来创建一组相关或相互依赖的对象,而无需关心它们的具体实现。在Java或其他...

    设计模式-简单工厂模式-例题

    ### 设计模式——简单工厂模式解析与应用实例 #### 一、简单工厂模式概述 简单工厂模式(Simple Factory Pattern)是一种常用的创建型设计模式。它提供了一种方式来封装对象的创建过程,使得整个系统更加灵活,...

Global site tag (gtag.js) - Google Analytics