一起来学设计模式-----创建型模式之抽象工厂

       学习了简单工厂,工厂方法模式,那什么是抽象工厂呢?工厂方法模式是在超类(IFactory)中定义一个工厂的抽象接口(CreateOperation),然后由子类负责创建具体对象;而抽象工厂则是维护一个产品家族,由子类定义产品被产生的方法,客户根据超类的接口开发。目前简单的理解,抽象工厂更多的就是基于多种产品的抽象和对象的创建。

     假设系统里有一个用户表,需求是插入和选择用户时根据用户的需求,可以保存在mysql 数据库或者Access数据库中,这时用工厂方法模式应该怎么样实现呢?

     首先使用面向对象的概念进行业务抽象,用户是一个类,使用mysql操作用户表是一个具体实践类,使用Access操作用户表是一个具体的实践类,操作类可以抽象成一个接口IUser类,根据工厂方法模式,则每个实践类都需要一个实际工厂是实例化,则需要2个具体工厂,这2个具体的工厂又能抽象一个接口IFactory类。客户端就可以根据实际情况,选择使用具体的工厂,创造出具体的类,操作user表。代码实现如下:


from abc import ABCMeta, abstractmethod


class User:
def __int__(self,id):
self.id = id

class IUser:
@abstractmethod
def InsertUser(self,user):
pass

@abstractmethod
def GetUser(self,id):
pass

class IFactory:
@abstractmethod
def CreateUser(self):
pass


class AccessUser(IUser):
    def InsertUser(self,user):
        print ("在access中为User表增加一条记录")

    def GetUser(self,id):
        print ("在access中为User表查询一条记录")

class MysqlUser(IUser):
    def InsertUser(self,user):
        print ("在mysql中为User表增加一条记录")

    def GetUser(self,id):
        print ("在mysql中为User表查询一条记录")

class MysqlFactory(IFactory):
def CreateUser(self):
return MysqlUser()

class AccessFactory(IFactory):
def CreateUser(self):
return AccessUser()

客户端调用的代码如下:

if __name__ == '__main__':
     user = User()
     factory = MysqlFactory()
     iu = factory.CreateUser()
     iu.InsertUser(user)
     iu.GetUser(1)

UML类图:

 

 

 

    如果此时,再加一个Department表,业务类似User一样的增加,在工厂类中,增加工厂创建实例对象的方法即可。则UML类图应该是下面这样的:

 

 

 

 

        代码实现如下:

class User:
    def __int__(self,id):
        self.id = id

class Department:
    def __int__(self,depName):
        self.depName = depName


class IUser:
    @abstractmethod
    def InsertUser(self,user):
        pass

    @abstractmethod
    def GetUser(self,id):
        pass


class IDepartment:
    @abstractmethod
    def InsertDepartment(self,dep):
        pass

    @abstractmethod
    def GetDepartment(self,depname):
        pass

class IFactory:
    @abstractmethod
    def CreateUser(self):
        pass

    @abstractmethod
    def CreateDepartment(self):
        pass

class AccessUser(IUser):
    def InsertUser(self,user):
        print ("在access中为User表增加一条记录")

    def GetUser(self,id):
        print ("在access中为User表查询一条记录")

class MysqlUser(IUser):
    def InsertUser(self,user):
        print ("在mysql中为User表增加一条记录")

    def GetUser(self,id):
        print ("在mysql中为User表查询一条记录")

class AccessDepartment(IDepartment):
    def InsertDepartment(self,dep):
        print ("在access中为Department表增加一条记录")

    def GetDepartment(self,id):
        print ("在access中为Department表查询一条记录")

class MysqlDepartment(IDepartment):
    def InsertDepartment(self,dep):
        print ("在mysql中为Department表增加一条记录")

    def GetDepartment(self,id):
        print ("在mysql中为Department表查询一条记录")
class MysqlFactory(IFactory):
    def CreateUser(self):
        return MysqlUser()

    def CreateDepartment(self):
        return MysqlDepartment()

class AccessFactory(IFactory):
    def CreateUser(self):
        return AccessUser()

    def CreateDepartment(self):
        return AccessDepartment()

客户端代码如下:

if __name__ == '__main__':
     user = User()
     factory = MysqlFactory()
     iu = factory.CreateUser()
     iu.InsertUser(user)
     iu.GetUser(1)

     dep = Department()
     asFactory = AccessFactory()
     idep = asFactory.CreateDepartment()
     idep.InsertDepartment(dep)
     idep.GetDepartment('loleina')

       这么一看,就已经实现了抽象工厂方法,工厂方法模式是定义一个用于创建对象的接口(IFactory),让子类(MysqlFactory,AccessFactory)去决定实例化哪一个类。而抽象工厂,是提供一个创建一系列相关或相互依赖对象的接口(IFactory内可以有多个产品的抽象),而无须指定它们的具体的类。

     抽象工厂最大的好处就是,客户端可以根据自己的需求,从不同的工厂中获取不同的产品对象,从而得到不同的产品。但是这个模式实际也是有很多缺点的,比如思考下此时加入一个新的表,要改动哪些呢?

下面以UML类图变化为例。灰色部分表示需要修改的地方。工厂类就得全部修改一遍。。。

 

相比如果增加一个工厂,代价是相对还少点。

 

        实际在真正的项目使用上,根据我进鹅厂看了这么多的业务代码经验,这类设计模式一般是不会被才采用到的,一般都是使用反射 + 配置文件(DB配置)+ 简单工厂来实现,这样增加产品类型时,只需要增加响应的产品,增加相关的配置,而无须修改任何代码。使用这个思路修改这个例子。

 

 

 代码实现如下:

class DateAccess:
    @staticmethod
    def CreateUser():
#DBType和DBTableName来自于配置文件或者DB配置 DBType
= 'Mysql' DBTableUser = 'User' instanceName = DBType +DBTableUser return eval(instanceName)() @staticmethod def CreatDepartment(): DBType = 'Mysql' DBTableDep = 'Department' instanceName = DBType + DBTableDep return eval(instanceName)()

客户端调用如下:

if __name__ == '__main__':
     user = User()
     iu = DateAccess.CreateUser()
     iu.InsertUser(user)
     iu.GetUser(1)

     dep = Department()
     idep =DateAccess.CreatDepartment()
     idep.InsertDepartment(dep)
     idep.GetDepartment('test')

 

posted @ 2017-08-19 17:29  loleina  阅读(386)  评论(0编辑  收藏  举报