简单工厂模式
- 对象创建和使用分离
- 根据参数返回实例对象
- 依赖配置文件
动机
生活:想要有一个苹果,就有一个苹果,不关注苹果怎么从种植到运输等生产过程,只关注怎么使用
抽象:只关注怎么使用对象,而不关注对象如何创建出来
定义
-
又称静态工厂方法,类创建型模式
-
可以根据参数的不同返回不同的实例
-
专门定义一个类来负责其他类的实例,被创建的实例通常具有共同的父类
结构
工厂角色:提供静态工厂方法,根据不同参数返回不同实例,把创建对象的过程封装在工厂🏭当中。
抽象产品角色:抽象出所有产品的共同属性,使用抽象层定义
具体产品角色:具体某个产品——苹果
分析
-
对象创建和对象本身处理业务分离,就是创建过程和使用过程分离,降低耦合度
-
使用静态定义,调用工厂类的方法用类名可直接调用,只需传入参数即可,无需知道对象创建细节
-
通过配置文件实现参数的修改,无需修改源码,实现开闭原则
实例
TVFactroy类
public class TVFactory
{
public static TV produceTV(String brand) throws Exception
{
if(brand.equalsIgnoreCase("Haier"))
{
System.out.println("电视机工厂生产海尔电视机!");
return new HaierTV();
}
else if(brand.equalsIgnoreCase("Hisense"))
{
System.out.println("电视机工厂生产海信电视机!");
return new HisenseTV();
}
else if(brand.equalsIgnoreCase("Tcl"))
{
System.out.println("电视机工厂生产Tcl电视机!");
return new TclTV();
}
else
{
throw new Exception("对不起,暂不能生产该品牌电视机!");
}
}
}
*注:这里返回的HaierTV()实际上是在TVFactory类中创建了HaierTV类的对象作为了TVFactory类成员变量
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("海信电视机播放中......");
}
}
Client类
模拟客户,用于体现简单工厂模式
public class Client
{
public static void main(String args[])
{
try
{
TV tv;
String brandName=XMLUtilTV.getBrandName();//使用XML文件进行参数的配置
tv=TVFactory.produceTV(brandName);
tv.play();
}
catch(Exception e)
{
System.out.println(e.getMessage());
}
}
}
XMLUtilTV
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("SimpleFactoryconfigTV.xml"));
//获取包含品牌名称的文本节点
NodeList nl = doc.getElementsByTagName("brandName");
Node classNode=nl.item(0).getFirstChild();
String brandName=classNode.getNodeValue().trim();
return brandName;
}
catch(Exception e)
{
e.printStackTrace();
return null;
}
}
}
xml文件
<?xml version="1.0"?>
<config>
<brandName>Haier</brandName>
</config>
运行结果
优点
- 实现对象创建和使用的分离
- 客户无需知道具体产品类的类名,只需知道对应参数即可
- 通过配置文件的引入符合开闭原则
缺点
- 工厂类职责过重
- 增加了类的个数(其实不算)
- 扩展困难,扩展新的产品要修改源代码,比如例子中要新增if-else语句,不符合开闭原则
- 使用静态工厂方法,工厂角色不能形成基于继承的等级结构——不能创建新的工厂
适用场景
- 工厂类负责创建的对象比较少
- 客户端只关心传入工厂类的参数,不关心如何创建对象
扩展
工厂类由抽象产品角色扮演,即合并工厂类和抽象产品角色