zoukankan      html  css  js  c++  java
  • 工厂模式与抽象工厂模式

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

    一、工厂模式

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

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

    这里写图片描述

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

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

    程序再次正确运行啦

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

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

  • 相关阅读:
    多选下拉框带搜索(aps.net)
    asp.net无刷新上传(带预览)
    http免费升级https 攻略(超简单)
    用JS获取地址栏参数的方法
    C#生成二维码
    update更新另一个字段
    自适应瀑布型布局(手机,PC全兼容)
    微信扫码支付.net版本
    常用css3技巧
    Repeater 嵌套,子级Repeater获取 父级Repeater 中的值
  • 原文地址:https://www.cnblogs.com/yinyoupoet/p/13287561.html
Copyright © 2011-2022 走看看