设计模式(一)—— 简单工厂模式

  • 时间:
  • 浏览:
  • 来源:互联网

文章目录

  • 前言
  • 正文
    • 一、定义
    • 二、情景假设
    • 三、情景分析
    • 四、模式结构及分析
      • 模式结构
      • 模式分析
        • 模式特点
        • 模式缺点
    • 五、使用情景
  • 总结


前言

文章内容主要参考了刘伟主编的《设计模式(第2版)》,同时也结合了自己的一些思考和理解,希望能帮到大家。

提示:一些设计模式的英文单词是有必要记住的噢~ 这在日后接触到各类模式代码的时候也能很快的反应过来,在我们编写各类模式的时候也能按照相应英文单词编写,既方便别人阅读也是方便了自己的阅读理解。


本篇文章针对的是设计模式中的工厂方法模式以及抽象工厂模式两大创建型模式的前导小课程学习----简单工厂模式,它是学习其他创建型模式的基础。应用也是比较的频繁的一种,但它并不属于23种模式中的一种。

正文

一、定义

简单工厂模式(Simple Factory Pattern):又称为静态工厂方法(Static Factory Method)模式,它属于类创建型模式

在这模式中可以根据参数的不同返回不同类的实例,其专门定义了一个类来负责创建其他类的实例,被创建的实例通常都具有共同的父类。

二、情景假设

某电视机厂专门生产各类电视机,比如海尔Haier电视机或者海信Hisense电视机,当输入任一类型的电视机,工厂就会生产这品牌电视机。

在看代码前我们可以自己脑补你会怎么编写?先写个Factory类,之后提供product创建电视机的方法,然后传入想要的电视机参数,返回的就是我们想要的电视机,然后我们可以对电视机进行各样的操作。接下来核对自己的想法叭。

三、情景分析

关于上面情景的类图
简单工厂模式类图
首先和我们所想的一样,首先应该会有个电视TV类,因为我们最后就是要生产出电视给客户

//抽象类TV
public interface TV
{
	public void play();
}

//具体实现类
//HaierTV
public class HaierTV implements TV
{
	public void play() {
		System.out.println("海尔电视机播放中!");
	}
}
//HisenseTV
public class HisenseTV implements TV
{
	public void play() {
		System.out.println("海信电视机播放中!");
	}
}

这里我们定义了TV接口之后具体品牌的电视机实现了这个接口。接着就是有个TVFactory电视工厂类用于按需求生产对应的电视机。

public class TVFactory {
	public static TV produceTV(String brand) throws Exception
	{
		if(brand.equals("Haier")) {
			System.out.println("电视机工厂生成海尔电视机");
			return new HaierTV();
		} else if(brand.equals("Hisense")) {
			System.out.println("电视机工厂生成海信电视机");
			return new HisenseTV();
		} else {
			throw new Exception("对不起,暂时不能生成该品牌电视机");
		}
	}
}

里面有个静态方法produceTV用于生产返回TV电视机。选择静态方法能够方便我们直接用TVFactory类使用方法,所以这就是为什么我们的简单工厂模式也叫静态工厂方法。

其实简单工厂模式大家理解起来不难,我们可能大家都会忽略的地方就是我们定义了一个TV接口用于去实现,而我们的TVFactory返回类型也是TV类,这样的设计其实是考虑客户端的统一操作性,所以对于模式的选择及设计我们除了要考虑背后的实现我们也不能忘记了客户端的具体情况。

接下来是客户端的代码:

public class Client
{
	public static void main(String args[])
	{
         try
         {
         	TV tv;
         	String brandName="Haier";
         	tv=TVFactory.produceTV(brandName);
         	tv.play();
         }
         catch(Exception e)
         {
         	System.out.println(e.getMessage());
         }
	}
}

我们可以看到,客户端通过电视工厂获取了接口TV类,我们便可以通过TV类的统一操作,这就是面向对象的多态。

四、模式结构及分析

模式结构

简单工厂模式结构
主要包含的角色

  • Factory:工厂角色
  • Product:抽象产品角色
  • ConcreteProduct:具体产品角色

模式分析

模式特点

  1. 将对象的创建和对象本身业务处理分离可以降低系统的耦合度,使得两者修改起来都相对容易。
    意思是客户端注重创建,我们只需要一个字符串,工厂就能返回具体电视,业务处理我们根本就看不到,也更好的维护。
  2. 在调用工厂类的工厂方法时,由于工厂方法是静态方法,使用起来很方便,可通过类名直接调用,而且只需要传入一个简单的参数即可,在实际开发中,还可以在调用时将所传入的参数保存在XML等格式的配置文件中,修改参数时无须修改任何Java源代码。
    即我们客户端可以看到我们运行其实是写死了字符串的值,而我们每次想去修改不同的品牌的时候就必须打开这个文件修改里面的字符串值,其实就是和源代码直接打交道了,这样其实风险很高,最好的办法就是通过配置文件传入我们想要品牌,我们直接和配置文件打交道这才是最稳妥的方式。

修改如下: 首先我们先要有一个工具类XMLUtilTV帮助我们读取XML文件并返回我们想要的内容给我们。

import javax.xml.parsers.*;
import org.w3c.dom.*;
import org.xml.sax.SAXException;
import java.io.*;
public class XMLUtilTV
{
    //该方法用于从XML配置文件中提取品牌名称,并返回该品牌名称
	public static String getBrandName()
	{
		try
		{
			//创建文档对象
			DocumentBuilderFactory dFactory = DocumentBuilderFactory.newInstance();
			DocumentBuilder builder = dFactory.newDocumentBuilder();
			Document doc;							
			doc = builder.parse(new File("configTV.xml")); 
		
			//获取包含品牌名称的文本节点
			NodeList nl = doc.getElementsByTagName("brandName");
            Node classNode = nl.item(0).getFirstChild();
            String brandName = classNode.getNodeValue().trim();
            
            return barndName;
           }   
           	catch(Exception e)
           	{
           		e.printStackTrace();
           		return null;
           	}
		}
}

接着就是我们的配置文件configTV.xml

<?xml version="1.0"?>
<config>
	<brandName>Haier</brandName>
</config>

最后就是我们的客户端的修改

public class Client
{
	public static void main(String args[])
	{
         try
         {
         	TV tv;
         	String brandName=XMLUtilTV.getBrandName();
         	tv=TVFactory.produceTV(brandName);
         	tv.play();
         }
         catch(Exception e)
         {
         	System.out.println(e.getMessage());
         }
	}
}

这样我们就可以修改配置文件去修改我们所想要的TV啦。

  1. 简单工厂模式最大的问题在于工厂类的职责相对过重,增加新的产品需要修改工厂类的判断逻辑,这一点与开闭原则是相违背的。
    这里我们就需要去理解开闭原则了,什么是开闭原则呢? 即对拓展开放,对修改闭合。这里我的理解就是拓展即我们想要对我们的各类东西进行增删改是不是方便而风险低的,我们能否在增删改的时候尽可能的不和源代码打交道,而是与文件、配置文件打交道。还是拿我们上面的例子,如果我们要增加一个格力电视机,这时候我们会修改些什么呢? 首先我们会写一个GreeTV类实现TV接口。然后最重要的我们会在TVFactory的静态方法多加一条判断语句,这里我们拓展一个品牌我只增加一个类文件这是对拓展开放的,但是我们要修改工厂方法里面的具体内容,这是违背了对修改闭合,真正理想情况是我们增加删除品牌只需要删除对应的类文件。所以简单工厂模式容易理解,但是最大的问题就是违背开闭原则。
  2. 简单工厂模式的要点在于:当你需要什么,只需要传入一个正确的参数,就可以获取你所需要的对象,而无须知道其创建细节。

模式缺点

  1. 工厂类集中了所有产品的创建逻辑,职责过重,一旦不能正常工作,整个系统都要受到影响
  2. 增加系统中类的个数(引入了新的工厂类),增加了系统的复杂度和理解难度
  3. 系统扩展困难,一旦添加新产品不得不修改工厂逻辑
  4. 由于使用了静态工厂方法,造成工厂角色无法形成基于继承的等级结构,工厂类不能得到很好地扩展。
    这里就是考虑的比较现实,各类品牌的产生不大可能由一个工厂去制作的,有时候工厂还有更加复杂的业务,仅有其中的静态方法去创建也限制了工厂的拓展。

五、使用情景

  • 工厂类负责创建的对象比较少:由于创建的对象较少,不会造成工厂方法中的业务逻辑太过复杂
  • 客户端只知道传入工厂类的参数,对于如何创建对象不关心:客户端既不需要关心创建细节,甚至连类名都不需要记住,只需要知道类型所对应的参数

总结

本篇文章主要介绍设计模式的前导—简单工厂模式,它并不属于23种设计模式,但是属于一个非常重要的入门设计模式。

本文链接http://www.dzjqx.cn/news/show-617260.html