博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
设计模式之抽象工厂模式
阅读量:6852 次
发布时间:2019-06-26

本文共 4817 字,大约阅读时间需要 16 分钟。

一、场景

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

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

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

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

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

二、定义和意图

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

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

三、结构

746656-20170225210904413-1383016860.png

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的产品Apublic class ProductA1 implements AbstractProductA {    public ProductA1(){        System.out.println("ProductA1");    }}//系列2的产品Apublic class ProductA2 implements AbstractProductA {    public ProductA2(){        System.out.println("ProductA2");    }}//系列1的产品Bpublic class ProductB1 implements AbstractProductB {    public ProductB1(){        System.out.println("ProductB1");    }}// 系列2的产品Bpublic class ProductB2 implements AbstractProductB {    public ProductB2(){        System.out.println("ProductB2");    }}

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

四、举例

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

746656-20170225210927038-979304163.png

通过客户端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

转载于:https://www.cnblogs.com/jaylon/p/6442849.html

你可能感兴趣的文章
我的友情链接
查看>>
我的友情链接
查看>>
子数组的和的最大值(包括升级版的首尾相连数组)
查看>>
LeetCode - Nth Highest Salary
查看>>
9.ORM数据访问
查看>>
在RHEL5下搭建SSH远程登录服务器
查看>>
使用Moblin SDK开发应用程序 -- Image Creator
查看>>
【我们都爱Paul Hegarty】斯坦福IOS8公开课个人笔记14 视图绘制Demo
查看>>
/dev/null &
查看>>
在Ubuntu上安装Node.js的Upstream版本
查看>>
扩展GridView控件(8) - 导出数据源的数据为Excel、Word或Text
查看>>
CISCO路由器配置基础(3)
查看>>
linux下通过串口登陆交换机
查看>>
微信公众平台群发规则说明
查看>>
LINUX下直接使用ISO文件
查看>>
第四章 apache的工作模式
查看>>
mysql备份和恢复总结
查看>>
软件明明已经删除 控制面板里还有名称
查看>>
深入浅出的SQL server 查询优化
查看>>
Hyper-V vNext新的虚拟机配置文件、配置版本
查看>>