• 设计模式之抽象工厂模式


    一、场景

    生活中总是存在着一些依赖于产品系列的问题,不同的系列中的产品可能相互不兼容,在使用时经常需要使用同一系列产品来完成工作。例如:单反摄像机的品牌有多种,如佳能、尼康等。单反摄像机配件是玩摄影的一个很大的开支,为了使拍出的照片更加漂亮,除了购买机身外还需要购买一些配件,如镜头、支架等。而不同品牌的这些配件是不相兼容,因此买了佳能的单反相机不能使用尼康的镜头。所以,一般购买某个品牌的单反后,就会购买其相应的配件。

    生活中还有一些别的相似场景,如:

    1. 电脑组装。电脑组装时需要考虑CUP、主板、内存等兼容性问题,不同的系列如Intell和AMD等有所不同,可能会引起兼容性问题。

    2. 操作系统软件。一个软件不能同时在不同操作系统上运行,必须针对不同的电脑系统开发相应的软件程序。如eclipse需要针对mac、window和linux设计软件,因为不同的系列使用的软件不同。

    3. 多个数据库切换问题。不同的数据库,如SQLServer、Access、MySql和Orcal等在连接方式、使用细节上有些不同,所以在编程中针对不同的数据库要定义相应的数据库访问操作。

    二、定义和意图

    抽象工厂模式:提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类。

    抽象工厂与工厂方法的区别是,抽象工厂是针对多个系列产品,而工厂方法是针对同个系列产品。

    三、结构

    AbstractFactory:定义了创建抽象产品对象的操作接口。

    
    public interface AbstractFactory {
        AbstractProductA createProductA();
        AbstractProductB createProductB();
    }
    

    ConcreteFactory:实现创建具体产品对象的操作

    
    public class ConcreteFactory1 implements AbstractFactory {
    
        @Override
    
        public AbstractProductA createProductA() {
    
            return new ProductA1();
    
        }
    
        @Override
    
        public AbstractProductB createProductB() {
    
            return new ProductB1();
    
        }
    
    }
    
    
    
    public class ConcreteFactory2 implements AbstractFactory {
    
        @Override
    
        public AbstractProductA createProductA() {
    
            return new ProductA2();
    
        }
    
        @Override
    
        public AbstractProductB createProductB() {
    
            return new ProductB2();
    
        }
    
    }
    
    

    AbstractProduct: 为一类产品对象声明接口

    
    public interface AbstractProductA {
    
    }
    
    
    
    public interface AbstractProductB {
    
    }
    
    

    ConcreteProduct:具体的产品对象

    
    //系列1的产品A
    
    public class ProductA1 implements AbstractProductA {
    
        public ProductA1(){
    
            System.out.println("ProductA1");
    
        }
    
    }
    
    //系列2的产品A
    
    public class ProductA2 implements AbstractProductA {
    
        public ProductA2(){
    
            System.out.println("ProductA2");
    
        }
    
    }
    
    //系列1的产品B
    
    public class ProductB1 implements AbstractProductB {
    
        public ProductB1(){
    
            System.out.println("ProductB1");
    
        }
    
    }
    
    // 系列2的产品B
    
    public class ProductB2 implements AbstractProductB {
    
        public ProductB2(){
    
            System.out.println("ProductB2");
    
        }
    
    }
    
    

    Client:使用AbstractFactory和AbstractProduct类声明的接口。

    四、举例

    以数据库的用户User和部门Dept的操作为例,不同数据库的SQL可能有些不同,因此需要为不同的数据库定义User和Dept的访问操作。

    通过客户端client调用不同的工厂获取不同数据库的访问方式。具体如下:

    DbFactory,创建访问不同数据库表的抽象工厂,

    
    public interface IFactory {
    
        IDept getIDept();
    
        IUser getIUser();
    
    }
    
    

    MySqlFactory访问Mysql数据的对象工厂,AccessFacotry是访问Access数据库数据的对象工厂。

    
    public class MysqlFactory implements IFactory {
    
        @Override
    
        public IDept getIDept() {
    
            return new MySqlDeptDao();
    
        }
    
        @Override
    
        public IUser getIUser() {
    
            return new MysqlUserDao();
    
        }
    
    }
    
    public class AccessFactory implements IFactory {
    
        @Override
    
        public IDept getIDept() {
    
            return new AccessDeptDao();
    
        }
    
        @Override
    
        public IUser getIUser() {
    
            return new AccessUserDao();
    
        }
    
    }
    
    

    访问User表的接口,和访问Dept的接口。

    
    public interface IUser {
    
        //添加用户
    
        boolean addUser(User user);
    
        //删除用户
    
        boolean delUser(User user);
    
    }
    
    public interface IDept {
    
        //插入部门
    
        boolean addDept(Dept dept);
    
        //删除部门
    
        boolean delDept(Dept dept);
    
    }
    
    

    具体实现:

    
    public class MySqlDeptDao implements IDept {
    
        @Override
    
        public boolean addDept(Dept dept) {
    
            System.out.println("mysql 中添加dept");
    
            return true;
    
        }
    
        @Override
    
        public boolean delDept(Dept dept) {
    
            System.out.println("mysql 中删除dept");
    
            return true;
    
        }
    
    }
    
    
    public class MysqlUserDao implements IUser{
    
        @Override
    
        public boolean addUser(User user) {
    
            System.out.println("mysql 中添加user");
    
            return true;
    
        }
    
    
    
        @Override
    
        public boolean delUser(User user) {
    
            System.out.println("mysql 中删除user");
    
            return true;
    
        }
    
    }
    
    
    
    public class AccessDeptDao implements IDept{
    
        @Override
    
        public boolean addDept(Dept dept) {
    
            System.out.println("access 中添加dept");
    
            return true;
    
        }
    
    
    
        @Override
    
        public boolean delDept(Dept dept) {
    
            System.out.println("access 中删除dept");
    
            return true;
    
        }
    
    }
    
    
    public class AccessUserDao implements IUser{
    
        @Override
    
        public boolean addUser(User user) {
    
            System.out.println("access 中添加user");
    
            return true;
    
        }
    
    
    
        @Override
    
        public boolean delUser(User user) {
    
            System.out.println("access 中删除user");
    
            return true;
    
        }
    
    }
    
    

    客户端的实现:

    
    public class Client {
    
        public static void main(String[] args){
    
            Dept dept = new Dept();
    
            //只要更换IFactory 就可以切换不同的数据库处理。这边可以采用配置和反射机制改进
    
            IFactory dbFactory = new MysqlFactory();
    
            IDept deptDao = dbFactory.getIDept();
    
            deptDao.addDept(dept);
    
        }
    
    }
    
    

    五、优缺点

    抽象工厂有以下优点:

    1. 易于交换产品系列。如上面的例子中,只要切换不同的具体工厂类就可以得到不同的数据库访问方式。

    2. 有利于保持产品的一致性。 因为具体工厂能够生产同一系列的产品,如MysqlFactory主要生产对Mysql数据库不同表访问的操作类,因此能够保持高度同一。

    3. 分离了具体类,实现了低耦合。将用户类和具体实现类分开,使得用户不知道对象的创建细节等,降低耦合性。

    抽象工厂的不足:

    1. 难以支持新来的产品。 例如上例中只支持对User表和Dept表的操作,如果有新的表需要操作,意味着需要在很多地方添加方法,破坏了开放-封闭原则。

    2. 要求每个产品系列都要有一个新的具体工厂子类,即使这些系列产品差别很小也要为不同系列创建具体子类。这样也很容易造成类爆炸问题。

    六、参考

    [1] 四人帮《设计模式》

    [2] 《大话设计模式》
    [3] http://www.cnblogs.com/java-my-life/archive/2012/03/28/2418836.html

  • 相关阅读:
    C#后台调用前台javascript的五种方法小结
    分页存储过程(一):分页获得单个表的数据 (未验证)
    第一章 单一职责原则 --(抄书)
    虚拟机--第二章java内存区域与内存溢出异常--(抄书)
    虚拟机--第一章走进java--(抄书)
    log4j的配置
    mybatis主配置文件详解
    js判断checkbox是否选中 .checked不管用
    简单的字幕添加方法
    Maven项目管理工具--简单实用与入门
  • 原文地址:https://www.cnblogs.com/jaylon/p/6442849.html
Copyright © 2020-2023  润新知