项目优化--从工厂方法到抽象工厂

本文探讨了工厂方法和抽象工厂的设计模式应用,通过实际项目案例对比两种模式的优缺点,详细介绍了如何利用抽象工厂结合配置文件实现系统的扩展性和灵活性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

* 序言

       写这篇博客之前,小编特意看了看之前自己写的有关设计模式的内容,当时刚刚接触设计模式,满心欢喜的希望自己可以有独特的认识,不过由于自己所接触内容的限制,当时理解仅仅停留在书面层次的概念中,不过每一次的成长都不是必然的,无论作用的大小,我相信每一次的接触和学习都是对自己有帮助的,欢迎大家指教!

       近期在项目中,自己再一次接触到了工厂方法和抽象工厂,并且在迭代中体会他们的优缺点,当然难免会有些地方小编用词不当,希望路过的基友不吝指教。


* 工厂方法

       工厂方法的特点:将产品创建的细节隐藏,生产单一的产品,她的优点是支持OCP(Open Closed Principle)原则,又熟悉了一下工厂方法的UML,如下:

这里写图片描述

       在该项目中,涉及到物料DAO我们尽量的抽取,对于物料的操作,采用工厂方法涉及模式,方便我们在更换数据库时,对扩展开发。如下:

这里写图片描述

       对于Dao的创建code自己便不再展示了,这里很贴合的用到了工厂方法。小编想说一下service和dao之间,其实这里也可以说是工厂方法,虽然manager只有一种实现方式,但是完全不影响我们日后的扩充,不过现在也没有这个必要。

   private ItemDao itemDao=null;   
   //region 逻辑层创建itemDao的实现,由直接new具体对象,到配置文件读取,无完全优化--viola--2018年6月28日11:11:33
   /**
    * 构造函数中,创建itemdao
    * 没有优化的
    */
    public ItemManagerImpl() {
       //调用工厂接口,向上转型

       //引入配置文件
       String className= XmlConfigRead.getInstance().getDaoFactory("item-dao-factory");
       ItemDaoFactory itemDaoFactory=null;
       try {
           //装载到内存,实例化
           itemDaoFactory=(ItemDaoFactory) Class.forName(className).newInstance();
       } catch (InstantiationException e) {
           e.printStackTrace();
       } catch (IllegalAccessException e) {
           e.printStackTrace();
       } catch (ClassNotFoundException e) {
           e.printStackTrace();
       }

       //创建对象
        itemDao=itemDaoFactory.createItemDao();
   }*/
   //endregion

* 抽象工厂

       上面这样的写法是没有问题的,不过当我们扩充另一种实现的service时,上面的大部分内容又要被我们再写一篇,这样有变动的时候需要修改的内容就会变得很多,代码的复用性显而易见。

这里写图片描述

       这时我们的需求便不再是创建单一的产品了,我们是要创建一系列的产品,不光是物料,可能还会涉及到订单模块,我们需要有一个地方可以进行统一的创建,这便需要我们再网上抽象,工厂方法已经不能满足了。因此需要引入抽象工厂,往往我们使用抽象工厂时,都会有一个很好的小伙伴在,便是配置文件,为什么要用配置文件呢?我们可以思考一个问题,如果我们在使用中new 了一个对象,那么我们便是依赖的具体,如果想要依赖抽象,那要如果做呢?

这里写图片描述

//ItemManagerImpl 中
//region 逻辑层创建itemDao实现,这里建立抽象工厂,统一创建,配置--viola--2018-6-28 11:13:14
    public ItemManagerImpl(){
        itemDao= (ItemDao) BeanFactoryNew.GetInstance().getDaoObject("itemDao");
    }
//BeanFactoryNew 中
package com.bjpowernode.drp.util;
import com.bjpowernode.drp.basedata.dao.ItemDao;
import com.bjpowernode.drp.basedata.manager.ItemManager;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import sun.security.jca.GetInstance;

import java.util.HashMap;
import java.util.Map;

/**
 * 抽象工厂中的具体工厂,创建不同的产品
 * 使用单例:
 * Created by Viola on 2018/6/28.
 */
public class BeanFactoryNew {
    private static BeanFactoryNew instance=new BeanFactoryNew();

    public static BeanFactoryNew GetInstance(){
        return instance;
    }

    //读取的配置文件
    private final String beansConfigFile="beans-config.xml";

    //承载配置文件
    private Document doc;

    //serviceMap
    private Map serviceMap=new HashMap();

    //daoMap
    private Map daoMap=new HashMap();

    /**
     * 初始化,读取配置文件
     */
    private BeanFactoryNew(){
        //读取配置文件
        try {
            doc=  new SAXReader().read(Thread.currentThread().getContextClassLoader().getResourceAsStream(beansConfigFile));
        } catch (DocumentException e) {
            e.printStackTrace();
            throw  new RuntimeException();
        }
    }

    /**
     * 根据产品编号取得service系列产品
     * @param serviceId
     * @return
     */
    public synchronized Object getServiceObject(String serviceId){
        //存在相关实例的话,返回
        if (serviceMap.containsKey(serviceId)){
            return serviceMap.get(serviceId);
        }
        //得到指定id节点对象
        Element serviceElt=(Element) doc.selectSingleNode("//service[@id=\""+serviceId+"\"]");
        //获得类名
        String serviceClassName=serviceElt.attributeValue("class");
        Object serviceClass=null;

        //实例化
        try {
            serviceClass= Class.forName(serviceClassName).newInstance();
            //放入map中
            serviceMap.put(serviceId,serviceClass);
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException();
        }
        return  serviceClass;
    }

    /**
     * 取得dao系列产品
     * @param daoId
     * @return
     */
    public synchronized Object getDaoObject(String daoId){
        //存在相关实例的话,返回
        if (serviceMap.containsKey(daoId)){
            return serviceMap.get(daoId);
        }
        //得到指定id节点对象
        Element serviceElt=(Element) doc.selectSingleNode("//dao[@id=\""+daoId+"\"]");
        //获得类名
        String daoClassName=serviceElt.attributeValue("class");
        Object daoClass=null;

        //实例化
        try {
            daoClass= Class.forName(daoClassName).newInstance();
            //放入map中
            serviceMap.put(daoId,daoClass);
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException();
        }
        return  daoClass;
    }   
}
//配置文件beansConfigFile:中
<?xml version="1.0" encoding="UTF-8" ?>
<beans>
    <!--物料dao,oracle实现-->
    <!--基于分层-->
    <!--service-->
    <service-class>
        <service id="itemManager" class="com.bjpowernode.drp.basedata.manager.ItemManagerImpl"></service>
    </service-class>

    <!--Dao-->
    <dao-class>
        <dao id="itemDao" class="com.bjpowernode.drp.basedata.dao.ItemDao4OracleImpl"></dao>
    </dao-class>
</beans>

* 原则

       可能存在好多设计模式,我们使用的不是很多,也不是很清楚,个人认为是没有什么好担心的,小编认为重要的是我们明白他们背后的一些原则,这对我们平时的开发和设计中有很大的指导作用。
1. 开闭原则
    a) 扩展开发,修改关闭
2. 里式代换原则
    a) 子类可以代替父类
3. 依赖倒转原则
    a) 面向抽象,非具体
4. 接口隔离原则
    a) 通信窄,单独接口
5. 迪米特法则
    a) 实体间的联系,尽可能小
6. 合成复用法则
    a) 用合成和聚合方法,代替继承


* End

       本文中的方案也不是最完善,每一次都有收获就好,我的目标是比上一次好点点,每一次都可以进步一点点。

       感谢您宝贵的阅读时间。

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值