设计模式(python实现)--抽象工厂模式(Abstract

2019-12-29  本文已影响0人  远行_2a22

动机(motivation)

模式定义

提供一个接口,让该接口负责创建一系列”相关或者相互依赖的对象“,无需指定它们具体的类。
——《设计模式》GoF

要点总结

UML

image.png

红色框表示稳定的部分,即抽象工厂基类,各个产品的基类。


例子-访问数据库

在访问数据库的例子中,由于DBAccess依赖了SqlConnectionSqlCommand,因此当业务需求,需要支持OracleMySql等数据库的时候,就需要修改DBAccess,违背了开闭原则、依赖导致原则。因此这里使用工厂模式、抽象工厂模式分别进行改进。

# -*- coding:utf-8 -*-

class SqlConnection(object):
    def set_connection(self):
        print('SqlConnection set_connection')


class SqlDataReader(object):
    def read(self):
        print('SqlDataReader read')


class SqlCommand(object):
    def start_connection(self, obj):
        print('SqlCommand start connection')


class DBAccess():
    # 访问数据库

    def get_employees(self):
        sql_connection = SqlConnection()
        sql_connection.set_connection()
        sql_command = SqlCommand()
        sql_command.start_connection(sql_connection)


if __name__ == '__main__':
    db = DBAccess()
    db.get_employees()

工厂方法实现

# -*- coding:utf-8 -*-

class DBConnectionBase(object):
    def set_connection(self):
        pass

class DBConnectionFactoryBase(object):
    def create_connection(self):
        pass

class DBCommandBase(object):
    def start_connection(self, obj):
        pass

class DBCommandFactoryBase(object):
    def create_command(self):
        pass


# 支持SQL
class SqlConnection(DBConnectionBase):
    def set_connection(self):
        print('SqlConnection set_connection')

class SqlConnectionFactory(DBConnectionFactoryBase):
    def create_connection(self):
        return SqlConnection()

class SqlCommand(DBCommandBase):
    def start_connection(self, obj):
        print('SqlCommand start connection')


class SqlCommandFactory(DBCommandFactoryBase):
    def create_command(self):
        return SqlCommand()


# 支持 Oracle
class OracleConnection(DBConnectionBase):
    def set_connection(self):
        print('OracleConnection set_connection')


class OracleConnectionFactory(DBConnectionFactoryBase):
    def create_connection(self):
        return OracleConnection()


class OracleCommand(DBCommandBase):
    def start_connection(self, obj):
        print('OracleCommand start connection')


class OracleCommandFactory(DBCommandFactoryBase):
    def create_command(self):
        return OracleCommand()


class DBAccess():
    # 访问数据库
    def get_employees(self, connection_factory, command_factory):
        db_connection = connection_factory.create_connection()
        db_connection.set_connection()
        db_command = command_factory.create_command()
        db_command.start_connection(db_connection)

if __name__ == '__main__':
    db = DBAccess()
    db.get_employees(SqlConnectionFactory(), SqlCommandFactory())

该例子中,用工厂方法虽然可以解决问题,但是有以下问题:

  1. 某个数据库相关的connectioncommand操作必须配套,因此如果有人这样调用,会出现不可预料的后果,因此必须进行类型检查,增加了代码的复杂度,和接口使用的心智负担。
db.get_employees(SqlConnectionFactory(), OracleCommand())
  1. 当一种数据库有n个行为,比如不仅仅有connectioncommand,还有read,write,那么要对应创建n个工厂,类的数量巨大、维护负担也随之而来。

因此需要使用抽象工厂模式,创建一系列相关或者相互依赖的对象

抽象工厂方法实现

# -*- coding:utf-8 -*-

class DBConnectionBase(object):
    def set_connection(self):
        pass

class DBCommandBase(object):
    def start_connection(self, obj):
        pass

class DBFactoryBase(object):
    def create_connection(self):
        pass

    def create_command(self):
        pass


# 支持SQL
class SqlConnection(DBConnectionBase):
    def set_connection(self):
        print('SqlConnection set_connection')

class SqlCommand(DBCommandBase):
    def start_connection(self, obj):
        print('SqlCommand start connection')


class SqlFactory(DBFactoryBase):
    def create_connection(self):
        return SqlConnection()

    def create_command(self):
        return SqlCommand()


# 支持 Oracle
class OracleConnection(DBConnectionBase):
    def set_connection(self):
        print('OracleConnection set_connection')


class OracleCommand(DBCommandBase):
    def start_connection(self, obj):
        print('OracleCommand start connection')

class OracleFactory(DBFactoryBase):
    def create_connection(self):
        return OracleConnection()

    def create_command(self):
        return OracleCommand()


class DBAccess():
    # 访问数据库

    def get_employees(self, db_factory):
        db_connection = db_factory.create_connection()
        db_connection.set_connection()
        db_command = db_factory.create_command()
        db_command.start_connection(db_connection)


if __name__ == '__main__':
    db = DBAccess()
    db.get_employees(SqlFactory())

抽象工厂中,将相互依赖的对象connectioncommand封装到了一起,从而使用起来的时候会成对创建,无需再担心connectioncommand不是一个数据库对象的问题,而且大大减少了类的数量。

对照UML分析

对照UML, 该例子中,
DBFactoryBase对应AbstractFactory
SqlFactory对应ConcreteFactory1
OracleFactory对应ConcreteFactory2
AbstractProductA对应DBConnectionBase
AbstractProductB对应DBCommandBase
SqlConnection 对应ConcreteProductA1
SqlCommand对应ConcreteProductB1

问题

  1. 当添加新的命令的时候,比如read,那么很多类都需要改变,那么类就不稳定了。
    答: 抽象工厂模式使用的前提是假设工厂中相互依赖的对象的数量是稳定的,即DBFactoryBase是稳定的。而抽象工厂模式适用于经常变换数据库需求,比如新支持mysqlmogodb等等, 这时候只需要扩展新的数据库工厂和具体实现类即可。
上一篇下一篇

猜你喜欢

热点阅读