抽象工厂模式的实质是提供「接口」,子类通过实现这些接口来定义具体的操作。
这些通用的接口如同协议一样,协议本身定义了一系列方法去描述某个类,子类通过实现这些方法从而实现了该类。
子类中不用关心这个类该是什么样子的,这些都有抽象类去定义,这就区分设计类和实现类两个过程,实现过程的解耦。
代码描述
描述一个这样的过程:有一个 GUIFactory,GUI 有 Mac 和 Windows 两种风格,现在需要创建两种不同风格的 Button,显示在 Application 中。
class GUIFactory(object): def __init__(self): self.screen = None def set_screen(self): raise NotImplementedError def get_size_from_screen(self, screen): if self.screen == 'retina': return '2560 x 1600' elif self.screen == 'full_hd': return '1920 x 1080'复制代码
定义 Mac 和 Windows 两种风格的 GUI。
class MacGUIFactory(GUIFactory): def __init__(self): super(MacGUIFactory, self).__init__() def set_screen(self): self.screen = 'retina' def set_attributes(*args, **kwargs): raise NotImplementedErrorclass WinGUIFactory(GUIFactory): def __init__(self): super(WinGUIFactory, self).__init__() def set_screen(self): self.screen = 'full_hd' def set_attributes(*args, **kwargs): raise NotImplementedError复制代码
所有 GUI 都需要设置屏幕的类型,否则在调用时候会抛出 NotImplementedError
的异常,抽象了设置 Button 属性的方法,让子类必须实现。
class MacButton(MacGUIFactory): def __init__(self): super(MacButton, self).__init__() self.set_screen() self.color = 'black' def set_attributes(self, *args, **kwargs): if 'color' in kwargs: self.color = kwargs.get('color') def verbose(self): size = self.get_size_from_screen(self.screen) print('''i am the {color} button of mac on {size} screen'''.format( color=self.color, size=size))class WinButton(WinGUIFactory): def __init__(self): super(WinButton, self).__init__() self.set_screen() self.color = 'black' def set_attributes(self, *args, **kwargs): if 'color' in kwargs: self.color = kwargs.get('color') def verbose(self): size = self.get_size_from_screen(self.screen) print('''i am the {color} button of win on {size} screen'''.format( color=self.color, size=size))复制代码
实现创建不同平台 Button 的方法, 需要根据屏幕的大小创建不同尺寸的 Button,才能有更好的显示效果。
这样就分别实现了两种不同 Button 的创建,还可以封装一个 Button 类来管理这两个不同的 Button。
class Button(object): @staticmethod def create(platform, *args, **kwargs): if platform.lower() == 'mac': return MacButton() elif platform.lower() == 'win': return WinButton()复制代码
创建两个不同平台的 Button,并且设置颜色属性
win_button = Button.create('win')mac_button = Button.create('mac')win_button.set_attributes(color='red')mac_button.set_attributes(color='blue')win_button.verbose()# >> i am the red button of win on 1920 x 1080 screenmac_button.verbose()# >> i am the blue button of mac on 2560 x 1600 screen复制代码
适用范围
以下情况可以适用抽象工厂模式:
- 独立于系统的模块
- 系统中各大类的模块
- 需要强调设计和实现分离的时候
- 只想显示接口并不想实现的时候
优缺点
优点:
- 具体产品从客户代码中被分离出来
- 容易改变产品的系列
- 将一个系列的产品族统一到一起创建
缺点:
- 在产品族中扩展新的产品是很困难的,它需要修改抽象工厂的接口