工厂模式与抽象工厂模式

在软件设计中,工厂模式和抽象工厂模式是比较常用的两种模式。下面来对其分别进行介绍。

一、工厂模式

工厂方法模式继承了简单工厂模式的优点,也弥补了简单工厂模式的缺点,符合了“开闭原则”。如果不清楚什么是简单工厂模式,不用担心,接下来所讲的内容不会涉及简单工厂模式。

工厂模式的基本原则是:工厂父类负责创建产品对象的公共接口,而工厂子类来负责生产具体的产品对象
是不是有点抽象,下面我们直接来看一个例子。

这里写图片描述

上图是一个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());
        }
    }
}

运行结果如图:
这里写图片描述

程序再次正确运行啦

总结:工厂模式与抽象工厂模式都属于创建型模式,在工厂模式中弥补了简单工厂模式的缺陷(不符合开闭原则),而在抽象工厂模式中弥补了工厂模式的不足(一个工厂只能生产一种产品)。

嘻嘻最后放一张萌猫壁纸
这里写图片描述

posted @ 2017-10-16 09:57  _吟游诗人  阅读(208)  评论(0编辑  收藏  举报