工厂模式三姐妹之抽象工厂模式

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


结构图:

例子:

场景:

你开发了一个软件,这个软件你数据库是用的SqlServer,你把这个软件卖出了,但是卖家叫你将数据库改为免费的 Mysql,如果你没有用设计模式或者你将所有和数据库相关代码写死再业务代码中,想想那是多么伤脑筋的一件事情,如果你用了抽象工厂模式,那么又将是一件非常轻松的事情,比如我们来拿用户表相关的操作来说说:

注释:代码中三个竖点标识代码中的上下文。

  • 面向过程的写法:
<?php
.
.
.

//直接把SqlServer操作用户的代码写个位置这里

.
.
.

看看上边的代码,如果你要将 SqlServer 数据库换成 Mysql ,拿将是多么庞大的工程啊,每一个涉及到和SqlServer交互的地方, 代码代码都需要修改,这是多么痛苦,还有可能因为不小心改错代码而产生错误。,这种肯定是不可取的。

  • 面向对象不用设计模式的写法:
.
.
.

//这里将SqlServer封装成类
$dataBase = new Datebase();
$dateBase->setUser();
.
.
.

其实这样写也不行,因为需要换库的时候还是需要改相关的对应封装的Datebase类的代码和涉及到和数据库交互的业务代码。

  • 用工厂方法模式:
<?php
abstruct class User{
    public abstruct function setUser();
    public abstruct function getUser();
}

class SqlServerUser extends User{
    public function setUser(){
        //SqlServer设置用户
    }
    
    public function getUser(){
        //SqlServer获取用户
    }
}

abstruct class UserFactory{
    public abstruct function createUser();
}

SqlServerUserFactory extends UserFactory{
    public function CreateUser(){
        return new SqlServerUser();
    }
}

//业务逻辑代码
.
.
.

$factory = new SqlServerUserFactory();
$database = $factory->CreateUser();

.
.
.

这样用工厂方法模式来实现,虽然比面向对象和不用设计模式实现的方式好多了(如果 DB 换成 mysql 的话,只需要添加 Mysql 的功能类和对应的工厂类,然后只需要将对应的 SqlServer 功能类的工厂类 的工厂换成 Mysql 功能类的工厂类就好了,但是这样还是很麻烦,因为系统不可能只有一个用户表,还有其它很多的表,这样的话就需要再每个涉及到表的地方去修改对应的工厂类,这样不仅工作量大,也还可能出问题)

  • 用抽象工厂模式来实现:

我们回忆一下抽象工厂模式的定义,是定义一系列相关或者是有依赖的对象的接口,这里的所有数据表的操作不就是一系列相关的对象吗,好,我们用代码来实现:

<?php
abstruct class DatabaseFactory{
    public abstruct function createUser();
    public abstruct function createOtherTable1();
    ...
}

class SqlServerFactory extends Database{
    public function createUser(){
        return new SqlServerUser();
    }
    
    public function createOtherTable1(){
        return new OtherTable1();
    }
}

abstruct class User{
    public abstruct function getUser();
    
    public abstruct function setUser();
}

class SqlServerUser extends User{
    public function getUser(){
        //获取用户
    }
    
    public function setUser(){
        //设置用户
    }
}

//业务逻辑代码
.
.
.

$database = new SqlServerFactory();
$user = $datebase->createUser();

.
.
.

看了上面用抽象工厂方法模式实现的代码是不是脑袋中有一个疑惑,这样写不是和工厂方法模式一样吗,工厂方法模式需要修改每一个 SqlServer 操作类对应的工程类为 Mysql 操作类对应的工厂类,比如说 new SqlServerUserFactory() 换成 new MysqlUserFactory(),抽象工厂方法模式也是需要这样做,只是修改的每个地方是一样的,比如说 修改new SqlServerFactory()new MysqlFactory()。等等,我们再仔细想一下,正是因为用抽象工厂方法模式写的代码修改的每个地方都一样,我们是不是可以将他写成一个全局变量或者是一个配置,修改的时候只需要修改这个全局变量或者是配置就好了(也能结合简单工厂类来实现全部替换)。好,我们来看看代码:

<?php
//现在我们如果要换库是不是只需要修改这儿就好了,不用去修改这么多代码,
//只需要写好Mysql相关的工厂类和具体功能类,
//直接替换define('DATABASE','SqlServerFactory') 
//为 define('DATABASE','MysqlFactory')就好了。
define('DATABASE','SqlServerFactory');
.
.
.

$database = new DATABASE();
$user = $datebase->createUser();

.
.
.

工厂模式三姐妹我就介绍完了这里总结一下:

  • 工厂类:生成的其它类的类叫做工厂类。
  • 简单工厂模式:给工厂类传入一个类型,工厂类通过这个类型来生成不同的类。但是这样如果需要拓展的话,就需要去修改工厂类,这样不满足开放封闭的原则。
  • 工厂方法模式:抽象业务需要的功能类和抽象对应功能类的工厂类,每一个功能类都对应一个工厂类,通过工厂类来生成对应的功能类。如果添加新的功能类,只需要新增一个继承抽象或者实现接口的类以及对应的工厂类就好,遵守开放关闭原则
  • 抽象工厂模式:将一系列相关的或者是依赖的类抽象为抽象工厂接口,然后具体不同的工厂类实现抽象工厂接口。具体的工厂类通过业务上下文来生成不同的功能类。这样的好处是如果需要替换这一系列相关的类是非常的简单。

Snail's Blog
请先登录后发表评论
  • 最新评论
  • 总共0条评论
  • 本博客使用免费开源的 laravel-bjyblog v5.5.1.3 -develop 搭建 © 2014-2018 www.snail-c.cn 版权所有 ICP证:蜀ICP备18023253号-1
  • 联系邮箱:459921737@qq.com