工厂模式与抽象工厂模式

来源:互联网 发布:施耐德网络面板接线图 编辑:程序博客网 时间:2024/06/01 21:52

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

一、工厂模式

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

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

这里写图片描述

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

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

程序再次正确运行啦

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

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

原创粉丝点击