在软件设计中,工厂模式和抽象工厂模式是比较常用的两种模式。下面来对其分别进行介绍。
一、工厂模式
工厂方法模式继承了简单工厂模式的优点,也弥补了简单工厂模式的缺点,符合了“开闭原则”。如果不清楚什么是简单工厂模式,不用担心,接下来所讲的内容不会涉及简单工厂模式。
工厂模式的基本原则是:工厂父类负责创建产品对象的公共接口,而工厂子类来负责生产具体的产品对象。
是不是有点抽象,下面我们直接来看一个例子。
上图是一个UML类图,实现了一个最基本的工厂模式。其中Client是客户类,当它需要生产鞋的时候,会去调用ShoeFactory中的produceShoes()
方法。
而鞋厂(ShoeFactory)本身是能生产男鞋(MaleShoes)和女鞋(FemaleShoes)的,因此在这里必然会使用到多态,即在ShoeFactory下还有两个子工厂(MaleShoesFactory和FemaleShoesFactory),子工厂负责创建真正的产品对象,而父工厂只负责提供一个接口。而当客户需要生产鞋的时候,只需申明一个ShoeFactory的变量指向一个MaleShoesFactory或者FemaleShoesFactory的对象即可。
然而如果仅仅是这样,仍旧是不符合开闭原则的,当需要生产男鞋或女鞋时我们仍然需要去修改代码,但是在此,我们引入了一个神奇的东西:利用DOM和java的反射,设计一个XML文件,保存需要新生成的类名,而再设计一个XML操作工具类XMLUtil,即可实现在程序运行时才能动态获取所需要生成的类。
是不是还是很抽象,没关系,看完代码就明白了。
下面是上面UML类图的实现代码。
先放上代码结构图:
Shoes
public interface Shoes {
public void wear();
}
MaleShoes
public class MaleShoes implements Shoes{
@Override
public void wear() {
System.out.println("Wear Male Shoes");
}
}
FemaleShoes
public class FemaleShoes implements Shoes{
@Override
public void wear() {
System.out.println("Wear Female Shoes");
}
}
ShoeFactory
public interface ShoeFactory {
public Shoes produceShoes();
}
MaleShoesFactory
public class MaleShoesFactory implements ShoeFactory{
@Override
public Shoes produceShoes() {
System.out.println("Produce Male Shoes");
return new MaleShoes();
}
}
FemaleShoesFactory
public class FemaleShoesFactory implements ShoeFactory {
@Override
public Shoes produceShoes() {
System.out.println("Produce Female Shoes");
return null;
}
}
XMLUtil
import javax.xml.parsers.*;
import org.xml.sax.SAXException;
import java.io.*;
import org.w3c.dom.*;
public class XMLUtil {
public static Object getBean(){
try{
//创建DOM文档对象
DocumentBuilderFactory dFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = dFactory.newDocumentBuilder();
Document doc;
doc = builder.parse(new File("config.xml"));
//获取包含类名的文本节点
NodeList nl = doc.getElementsByTagName("className");
Node classNode = nl.item(0).getFirstChild();
String cName = classNode.getNodeValue();
//通过类名生成实例对象并将其返回
Class c = Class.forName(cName);
Object obj = c.newInstance();
return obj;
}catch(Exception e){
e.printStackTrace();
return null;
}
}
}
config.xml
<?xml version="1.0" encoding="UTF-8"?>
<config>
<className>com.zk.factory.MaleShoesFactory</className>
</config>
接下来就可以运行Client类进行试验了
public class Client {
public static void main(String[] args) {
try{
Shoes shoes;
ShoeFactory factory;
factory = (ShoeFactory) XMLUtil.getBean();
shoes = factory.produceShoes();
shoes.wear();
}catch(Exception e){
System.out.println(e.getMessage());
}
}
}
运行结果为:
可以看见,程序正确执行并创建了MaleShoesFactory的实例,并成功调用了其produceShoes()
方法和wear()
方法。
需要注意的是,在XML配置文件中,如果xml文件不和java代码保存在同一个包下,一定要记得加上包名,否则可能会出现类名找不到的错误。
二、抽象工厂模式
前面讲了工厂模式,有没有发现其还是有缺点,比如说鞋厂只能生产同一款鞋,而设想下一家代加工的鞋厂,里面可能既加工Adidas的鞋,同时还加工Nike的鞋,或者再想想,Nike和Adidas公司在生产鞋的同时,都还在生产衣服,那么,这种情况用工厂模式就不能做到了,因此产生了抽象工厂模式。
抽象工厂模式的适用范围比工厂模式更加广泛,它与工厂模式最大的区别在于:
工厂模式中一个工厂只能生产一种产品,而抽象工厂可以生产多个。
下面来看一个例子:
这里有一家劳工工厂,里面分别为Nike和Adidas代加工产品,而Nike和Adidas都需要该厂为其加工衣服和鞋子。
下面放上代码:
这是代码结构图:
Shoes
public interface Shoes {
public void wear();
}
AdidasShoes
public class AdidasShoes implements Shoes{
@Override
public void wear() {
System.out.println("Wear Adidas Shoes");
}
}
NikeShoes
public class NikeShoes implements Shoes{
@Override
public void wear() {
System.out.println("Wear Nike Shoes");
}
}
Clothes
public interface Clothes {
public void wear();
}
NikeClothes
public class NikeClothes implements Clothes{
@Override
public void wear() {
System.out.println("Wear Nike Clothes");
}
}
AdidasClothes
public class AdidasClothes implements Clothes{
@Override
public void wear() {
System.out.println("Wear Adidas Clothes");
}
}
LabourFactory
public interface LabourFactory {
Shoes produceShoes();
Clothes produceClothes();
}
NikeFactory
public class NikeFactory implements LabourFactory{
@Override
public Shoes produceShoes() {
System.out.println("Produce Nike Shoes");
return new NikeShoes();
}
@Override
public Clothes produceClothes() {
System.out.println("Produce Nike Clothes");
return new NikeClothes();
}
}
AdidasFactory
public class AdidasFactory implements LabourFactory{
@Override
public Shoes produceShoes() {
System.out.println("Produce Adidas Shoes");
return new AdidasShoes();
}
@Override
public Clothes produceClothes() {
System.out.println("Produce Adidas Clothes");
return new AdidasClothes();
}
}
XMLUtil
import javax.xml.parsers.*;
import org.xml.sax.SAXException;
import java.io.*;
import org.w3c.dom.*;
public class XMLUtil {
public static Object getBean(){
try{
//创建DOM文档对象
DocumentBuilderFactory dFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = dFactory.newDocumentBuilder();
Document doc;
doc = builder.parse(new File("config_abstract.xml"));
//获取包含类名的文本节点
NodeList nl = doc.getElementsByTagName("className");
Node classNode = nl.item(0).getFirstChild();
String cName = classNode.getNodeValue();
//通过类名生成实例对象并将其返回
Class c = Class.forName(cName);
Object obj = c.newInstance();
return obj;
}catch(Exception e){
e.printStackTrace();
return null;
}
}
}
config_abstract.xml
<?xml version="1.0" encoding="UTF-8"?>
<config>
<className>com.zk.abstractFactory.AdidasFactory</className>
</config>
接下来同样的写一个Client类来试着运行看看效果。
public class Client {
public static void main(String[] args) {
try{
LabourFactory lFactory;
Shoes shoes;
Clothes clothes;
lFactory = (LabourFactory) XMLUtil.getBean();
shoes = lFactory.produceShoes();
clothes = lFactory.produceClothes();
shoes.wear();
clothes.wear();
}catch (Exception e) {
System.out.println(e.getMessage());
}
}
}
运行结果如图:
程序再次正确运行啦
总结:工厂模式与抽象工厂模式都属于创建型模式,在工厂模式中弥补了简单工厂模式的缺陷(不符合开闭原则),而在抽象工厂模式中弥补了工厂模式的不足(一个工厂只能生产一种产品)。
嘻嘻最后放一张萌猫壁纸