简单工厂模式(Simple factory Pattern),又称静态工厂方法(Static Factory Method),属于创新型模式,但它不属于GoF23个设计模式其一。
一、模式动机:
有时需要创建一些来自相同父类的类的实例。
二、定义:
在简单工厂模式中,可以根据参数的不同返回不同类的实例。简单工厂模式专门定义一个类来负责其他类的实例,被创建的实例通常都具有共同的父类。
三、模式结构:
*1.Factory(工厂角色)
(1)工厂角色即工厂类,负责实现创建所有实例的内部逻辑;
(2)工厂类可以被外界直接调用,创建所需的产品对象;
(3)工厂类中提供了静态的工厂方法factoryMethod(),它返回一个抽象产品的类,所有的具体产品都是抽象产品的子类。
2.Produce(抽象产品角色)
(1)抽象产品角色是简单工厂模式所创建的所有对象的父类,负责描述所有实例共有的公共接口;
(2)抽象产品的引入将提高系统的灵活性,使得在工厂类中只需定义一个工厂方法。因为所有的具体产品都是抽象产品的子类。
3.ConcreteProduce(具体产品角色)
(1)具体产品角色是简单工厂模式的创建目标;
(2)具体类中所创建的对象都充当对应具体类的实例;
(3)每一个具体产品角色都继承了抽象产品角色,需要实现定义在抽象产品角色里的抽象方法。
四、模式分析:
简单工厂模式的要点在于----当你需要什么,只需要传入一个正确的参数,就可以获得你所需要的对象,而无需知道其创建的细节。
五、模式实例与解析:
1.实例说明
某电视机厂专为各种电视机品牌代工生产各类电视机,当需要海尔牌电视机时只需要在调用该工厂的工厂方法时传入参数Haier,需要海信电视机时只需要在调用该工厂的工厂方法时传入参数Hisense,工厂可以根据不同的参数返回不同品牌的电视机。
2.实例类图
3.实例代码
(1)TV接口
public interface TV {
public void play();
}
(2)HaierTV类
public class HaierTV implements TV{
public void play(){
System.out.println("海尔电视机播放中......");
}
}
(3)HisenseTV类
public class HisenseTV implements TV{
public void play(){
System.out.println("海信电视机播放中......");
}
}
(4)TCLTV类
public class TCLTV implements TV{
public void play(){
System.out.println("TCL电视机播放中......");
}
}
(5)TVFactory类
public class TVFactory {
public static TV productTV(String brand){
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 {
return (TV) new Exception("暂不生产该品牌电视机。");
}
}
}
4.辅助代码
(1)XMLUtil类
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import java.io.File;
public class XMLUtil {
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();
return brandName;
}
catch(Exception e)
{
e.printStackTrace();
return null;
}
}
}
(2)配置文件configTV.xml
(路径配置在工程下面)
<?xml version="1.0" encoding="UTF-8" ?>
Haier
(3)客户端测试类Client
public class Client {
public static void main(String[] args) {
try {
TV tv;
String brandName = XMLUtil.getBrandName();
tv = TVFactory.productTV(brandName);
tv.play();
} catch (Exception e) {
System.out.println(e.getMessage());
}
}
}
5.实例结果与分析
(1)如果在配置文件configTV.xml中将
(2)如果将
TCL电视机同理.....
(3)分析:如果希望系统支持新的电视机产品,则需要新增加一个具体类,同时还要修改TVFactory中的工厂方法。
六、模式的优点:
1.可以决定在什么时候创建哪一个产品类的实例,客户端可以免除直接创建产品对象的责任。
2.客户端无需知道所创建的具体类的类名,只需要知道具体产品类对应的参数即可,减少了使用者的记忆量。
3.通过引入配置文件,可以在不修改任何客户端代码的情况下更换和增新新的具体产品类,在一定程度上提高了系统的灵活性。
七、模式的缺点
1.由于工厂类集中了所有产品创建逻辑,一旦不能工作,整个系统都将受到影响。
2.由于新加一个产品就得新加一个产品具体类,所以在一定程度上增加了系统的复杂性和理解难度
3.系统扩展困难,一旦添加新产品就不得不修改共产逻辑,在产品类型较多时,有可能造成工厂逻辑过于复杂,不利于系统的扩展和维护。
4.简单工厂模式由于使用了静态工厂方法造成工厂角色无法形成基于继承的等级结构。
八、模式适用环境:
(1)工厂类负责创建的对象较少
(2)客户端只知道传入工厂的参数,对于如何创建对象并不关心;客户端既不需要关心细节,甚至连类名也不需要记住,只需要记住类型所对应的参数即可。