跳转到内容

抽象工厂

25% developed
维基教科书,开放书籍,开放世界

计算机科学设计模式
抽象工厂
适配器

抽象工厂模式提供了一种封装一组具有共同主题的单个工厂的方法,而无需指定它们的具体类。在正常使用中,客户端软件创建一个抽象工厂的具体实现,然后使用工厂的通用接口来创建属于该主题的具体对象。客户端不知道(也不关心)它从每个这些内部工厂获得哪些具体对象,因为它只使用它们的产品的通用接口。这种模式将一组对象的实现细节与它们的通用使用分开,并依赖于对象组合,因为对象创建是在工厂接口中公开的方法中实现的。一个例子是抽象工厂类DocumentCreator,它提供创建多个产品的接口(例如createLetter()createResume())。该系统将拥有任意数量的DocumentCreator类的派生具体版本,例如FancyDocumentCreatorModernDocumentCreator,每个版本都有createLetter()createResume()的不同实现,它们将创建一个对应的对象,例如FancyLetterModernResume。这些产品中的每一个都派生自一个简单的抽象类,例如LetterResume,客户端知道这些类。客户端代码将获取DocumentCreator的适当实例,并调用其工厂方法。每个生成的都是从同一个DocumentCreator实现创建的,并且将共享一个共同的主题(它们将都是花哨的或现代的对象)。客户端只需要知道如何处理抽象的LetterResume类,而不需要知道它从具体工厂获得的特定版本。

工厂是代码中构建对象的具体类的所在位置。使用该模式的目的是将对象的创建与它们的用法隔离开,并创建相关对象的族,而无需依赖它们的具体类。这允许引入新的派生类型,而无需更改使用基类的代码。

使用这种模式可以在不更改使用它们的代码的情况下,甚至在运行时,互换具体实现。然而,使用这种模式,就像使用类似的设计模式一样,可能会导致不必要的复杂性和在最初编写代码时的额外工作。此外,更高层次的隔离和抽象会导致系统更难调试和维护。因此,与所有软件设计一样,必须仔细评估权衡取舍。

定义

抽象工厂模式的本质是“提供一个接口来创建相关或依赖对象的族,而无需指定它们的具体类”。

用法

工厂决定要创建的实际具体对象类型,并且在此处实际创建对象(例如,在 C++ 中,通过new运算符)。但是,工厂只返回对创建的具体对象的抽象指针。

通过让客户端请求工厂对象创建所需抽象类型对象并返回指向该对象的抽象指针,这将客户端代码与对象创建隔离开来。

由于工厂只返回抽象指针,因此客户端代码(从工厂请求对象的代码)不知道(并且不负担)刚刚创建的对象的实际具体类型。然而,具体对象的类型(以及因此的具体工厂)是抽象工厂知道的;例如,工厂可能从配置文件中读取它。客户端不需要指定类型,因为它已经在配置文件中指定了。特别是,这意味着

  • 客户端代码完全不知道具体类型,不需要包含任何与之相关的头文件或类声明。客户端代码只处理抽象类型。具体类型的对象确实是由工厂创建的,但客户端代码只通过它们的抽象接口访问这些对象。
  • 添加新的具体类型是通过修改客户端代码以使用不同的工厂来完成的,这种修改通常是一行代码,在一个文件中。然后,不同的工厂创建不同具体类型的对象,但仍然返回与以前相同抽象类型的指针 - 因此将客户端代码与更改隔离开来。这比修改客户端代码来实例化新类型要容易得多,这将需要更改代码中创建新对象的每个位置(以及确保所有这些代码位置也都了解新具体类型,例如通过包含具体类头文件)。如果所有工厂对象都全局存储在一个单例对象中,并且所有客户端代码都通过单例访问适当的工厂来创建对象,那么更改工厂就像更改单例对象一样容易。

结构

类图

GuiFactory接口上的createButton方法返回Button类型的对象。返回的Button的具体实现取决于哪个GuiFactory实现正在处理方法调用。

注意,为了简洁起见,此类图只显示创建一种类型对象的类关系。

Lepus3图表 (图例)

UML图

实现

输出应该是“我是 WinButton”或“我是 OSXButton”,具体取决于使用了哪种工厂。请注意,应用程序不知道它被赋予了哪种 GUIFactory,甚至不知道工厂创建了哪种 Button。

C# 实现
/* GUIFactory example -- */

using System;
using System.Configuration;

namespace AbstractFactory {
    public interface IButton {
        void Paint();
    }

    public interface IGUIFactory {
        IButton CreateButton();
    }

    public class OSXButton : IButton { // Executes fourth if OS:OSX
        public void Paint() {
            System.Console.WriteLine("I'm an OSXButton");
        }
    }

    public class WinButton : IButton { // Executes fourth if OS:WIN
        public void Paint() {
            System.Console.WriteLine("I'm a WinButton");
        }
    }

    public class OSXFactory : IGUIFactory { // Executes third if OS:OSX
        IButton IGUIFactory.CreateButton() {
            return new OSXButton();
        }
    }

    public class WinFactory : IGUIFactory { // Executes third if OS:WIN
        IButton IGUIFactory.CreateButton() {
            return new WinButton();
        }
    }

    public class Application {
        public Application(IGUIFactory factory) {
            IButton button = factory.CreateButton();
            button.Paint();
        }
    }

    public class ApplicationRunner {
        static IGUIFactory CreateOsSpecificFactory() { // Executes second
            // Contents of App.Config associated with this C# project
            //<?xml version="1.0" encoding="utf-8" ?>
            //<configuration>
            //  <appSettings>
            //    <!-- Uncomment either Win or OSX OS_TYPE to test -->
            //    <add key="OS_TYPE" value="Win" />
            //    <!-- <add key="OS_TYPE" value="OSX" /> -->
            //  </appSettings>
            //</configuration>
            string sysType = ConfigurationSettings.AppSettings["OS_TYPE"];
            if (sysType == "Win") {
                return new WinFactory();
            } else {
                return new OSXFactory();
            }
        }

        static void Main() { // Executes first
            new Application(CreateOsSpecificFactory());
            Console.ReadLine();
        }
    }
}
C++ 实现
/* GUIFactory example */

#include <iostream>

class Button {
public:
    virtual void paint() = 0;
    virtual ~Button() { }
};

class WinButton : public Button {
public:
    void paint() {
        std::cout << "I'm a WinButton";
    }
};

class OSXButton : public Button {
public:
    void paint() {
        std::cout << "I'm an OSXButton";
    }
};

class GUIFactory {
public:
    virtual Button* createButton() = 0;
    virtual ~GUIFactory() { }
};

class WinFactory : public GUIFactory {
public:
    Button* createButton() {
        return new WinButton();
    }

    ~WinFactory() { }
};

class OSXFactory : public GUIFactory {
public:
    Button* createButton() {
        return new OSXButton();
    }
         
    ~OSXFactory() { }
};

class Application {
public:
    Application(GUIFactory* factory) {
        Button* button = factory->createButton();
        button->paint();
        delete button;
        delete factory;
    }
};

GUIFactory* createOsSpecificFactory() {
    int sys;
    std::cout << "Enter OS type (0: Windows, 1: MacOS X): ";
    std::cin >> sys;

    if (sys == 0) {
        return new WinFactory();
    } else {
        return new OSXFactory();
    }
}

int main() {
    Application application(createOsSpecificFactory());

    return 0;
}
Java 实现
/* GUIFactory example -- */

interface Button {
    void paint();
}

interface GUIFactory {
    Button createButton();
}

class WinFactory implements GUIFactory {
    public Button createButton() {
        return new WinButton();
    }
}

class OSXFactory implements GUIFactory {
    public Button createButton() {
        return new OSXButton();
    }
}

class WinButton implements Button {
    public void paint() {
        System.out.println("I'm a WinButton");
    }
}

class OSXButton implements Button {
    public void paint() {
        System.out.println("I'm an OSXButton");
    }
}

class Application {
    public Application(GUIFactory factory) {
        Button button = factory.createButton();
        button.paint();
    }
}

public class ApplicationRunner {
    public static void main(String[] args) {
        new Application(createOsSpecificFactory());
    }

    public static GUIFactory createOsSpecificFactory() {
        int sys = readFromConfigFile("OS_TYPE");
        if (sys == 0) return new WinFactory();
        else return new OSXFactory();
    }
}
Objective-C 实现
/* GUIFactory example -- */

#import <Foundation/Foundation.h>

@protocol Button <NSObject>
- (void)paint;
@end

@interface WinButton : NSObject <Button>
@end

@interface OSXButton : NSObject <Button>
@end

@protocol GUIFactory
- (id<Button>)createButton;
@end

@interface WinFactory : NSObject <GUIFactory>
@end

@interface OSXFactory : NSObject <GUIFactory>
@end

@interface Application : NSObject
- (id)initWithGUIFactory:(id)factory;
+ (id)createOsSpecificFactory:(int)type;
@end

@implementation WinButton
- (void)paint {
    NSLog(@"I am a WinButton.");
}
@end

@implementation OSXButton
- (void)paint {
    NSLog(@"I am a OSXButton.");
}
@end

@implementation WinFactory
- (id<Button>)createButton {
    return [[[WinButton alloc] init] autorelease];
}
@end

@implementation OSXFactory
- (id<Button>)createButton {
    return [[[OSXButton alloc] init] autorelease];
}
@end

@implementation Application
- (id)initWithGUIFactory:(id<GUIFactory>)factory {
    if (self = [super init]) {
        id button = [factory createButton];
        [button paint];
    }
    return self;
}
+ (id<GUIFactory>)createOsSpecificFactory:(int)type {
    if (type == 0) {
        return [[[WinFactory alloc] init] autorelease];
    } else {
        return [[[OSXFactory alloc] init] autorelease];
    }
}
@end

int main(int argc, char* argv[]) {
    @autoreleasepool {
        [[Application alloc] initWithGUIFactory:[Application createOsSpecificFactory:0]];// 0 is WinButton
    }
    return 0;
}
Lua 实现
--[[
    Because Lua is a highly dynamic Language, an OOP scheme is implemented by the programmer.
    The OOP scheme implemented here implements interfaces using documentation.
   
   
    A Factory Supports:
     - factory:CreateButton()
     
    A Button Supports:
     - button:Paint()
]]

-- Create the OSXButton Class
do
    OSXButton = {}
    local mt = { __index = OSXButton }
   
    function OSXButton:new()
        local inst = {}
        setmetatable(inst, mt)
        return inst
    end
   
    function OSXButton:Paint()
        print("I'm a fancy OSX button!")
    end
end

-- Create the WinButton Class
do
    WinButton = {}
    local mt = { __index = WinButton }
   
    function WinButton:new()
        local inst = {}
        setmetatable(inst, mt)
        return inst
    end
   
    function WinButton:Paint()
        print("I'm a fancy Windows button!")
    end
end

-- Create the OSXGuiFactory Class
do
    OSXGuiFactory = {}
    local mt = { __index = OSXGuiFactory }
   
    function OSXGuiFactory:new()
        local inst = {}
        setmetatable(inst, mt)
        return inst
    end
   
    function OSXGuiFactory:CreateButton()
        return OSXButton:new()
    end
end

-- Create the WinGuiFactory Class
do
    WinGuiFactory = {}
    local mt = { __index = WinGuiFactory }
   
    function WinGuiFactory:new()
        local inst = {}
        setmetatable(inst, mt)
        return inst
    end
   
    function WinGuiFactory:CreateButton()
        return WinButton:new()
    end
end

-- Table to keep track of what GuiFactories are available
GuiFactories = {
    ["Win"] = WinGuiFactory,
    ["OSX"] = OSXGuiFactory,
}

--[[ Inside an OS config script ]]
OS_VERSION = "Win"

--[[ Using the Abstract Factory in some the application script ]]

-- Selecting the factory based on OS version
MyGuiFactory = GuiFactories[OS_VERSION]:new()

-- Using the factory
osButton = MyGuiFactory:CreateButton()
osButton:Paint()
PHP 实现

此抽象工厂创建书籍。

/*
 * BookFactory classes
*/
abstract class AbstractBookFactory {
    abstract function makePHPBook();
    abstract function makeMySQLBook();
}

class OReillyBookFactory extends AbstractBookFactory {
    private $context = "OReilly";
    function makePHPBook() {
        return new OReillyPHPBook;
    }
    function makeMySQLBook() {
        return new OReillyMySQLBook;
    }
}

class SamsBookFactory extends AbstractBookFactory {
    private $context = "Sams";
    function makePHPBook() {
        return new SamsPHPBook;
    }
    function makeMySQLBook() {
        return new SamsMySQLBook;
    }
}

/*
 *   Book classes
*/
abstract class AbstractBook {
    abstract function getAuthor();
    abstract function getTitle();
}

abstract class AbstractMySQLBook extends AbstractBook {
    private $subject = "MySQL";
}

class OReillyMySQLBook extends AbstractMySQLBook {
    private $author;
    private $title;
    function __construct() {
        $this->author = 'George Reese, Randy Jay Yarger, and Tim King';
        $this->title = 'Managing and Using MySQL';
    }
    function getAuthor() {
        return $this->author;
    }
    function getTitle() {
        return $this->title;
    }
}

class SamsMySQLBook extends AbstractMySQLBook {
    private $author;
    private $title;
    function __construct() {
        $this->author = 'Paul Dubois';
        $this->title = 'MySQL, 3rd Edition';
    }
    function getAuthor() {
        return $this->author;
    }
    function getTitle() {
        return $this->title;
    }
}

abstract class AbstractPHPBook extends AbstractBook {
    private $subject = "PHP";
}

class OReillyPHPBook extends AbstractPHPBook {
    private $author;
    private $title;
    private static $oddOrEven = 'odd';
    function __construct() {
        //alternate between 2 books
        if ('odd' == self::$oddOrEven) {
            $this->author = 'Rasmus Lerdorf and Kevin Tatroe';
            $this->title = 'Programming PHP';
            self::$oddOrEven = 'even';
        } else {
            $this->author = 'David Sklar and Adam Trachtenberg';
            $this->title = 'PHP Cookbook';
            self::$oddOrEven = 'odd';
        }
    }
    function getAuthor() {
        return $this->author;
    }
    function getTitle() {
        return $this->title;
    }
}

class SamsPHPBook extends AbstractPHPBook {
    private $author;
    private $title;
    function __construct() {
        //alternate randomly between 2 books
        mt_srand((double)microtime() * 10000000);
        $rand_num = mt_rand(0, 1);

        if (1 > $rand_num) {
            $this->author = 'George Schlossnagle';
            $this->title = 'Advanced PHP Programming';
        }
        else {
            $this->author = 'Christian Wenz';
            $this->title = 'PHP Phrasebook';
        }
    }
    function getAuthor() {
        return $this->author;
    }
    function getTitle() {
        return $this->title;
    }
}

/*
 *   Initialization
*/

writeln('BEGIN TESTING ABSTRACT FACTORY PATTERN');
writeln('');

writeln('testing OReillyBookFactory');
$bookFactoryInstance = new OReillyBookFactory;
testConcreteFactory($bookFactoryInstance);
writeln('');

writeln('testing SamsBookFactory');
$bookFactoryInstance = new SamsBookFactory;
testConcreteFactory($bookFactoryInstance);

writeln("END TESTING ABSTRACT FACTORY PATTERN");
writeln('');

function testConcreteFactory($bookFactoryInstance) {
    $phpBookOne = $bookFactoryInstance->makePHPBook();
    writeln('first php Author: '.$phpBookOne->getAuthor());
    writeln('first php Title: '.$phpBookOne->getTitle());

    $phpBookTwo = $bookFactoryInstance->makePHPBook();
    writeln('second php Author: '.$phpBookTwo->getAuthor());
    writeln('second php Title: '.$phpBookTwo->getTitle());

    $mySqlBook = $bookFactoryInstance->makeMySQLBook();
    writeln('MySQL Author: '.$mySqlBook->getAuthor());
    writeln('MySQL Title: '.$mySqlBook->getTitle());
}

function writeln($line_in) {
    echo $line_in."<br/>";
}
Scala 实现

此抽象工厂创建音乐家。

// concrete implementation
class DrummerFactory extends MusicianAbstractFactory {
  def create(): Musician = new Drummer()
}

class GuitarPlayerFactory extends MusicianAbstractFactory {
  def create(): Musician = new GuitarPlayer()
}

class GuitarPlayer extends Musician {
  def play(song: String) {
    println(s"I'm guitar player and I play $song")
  }
}
class Drummer extends Musician {
  def play(song: String) {
    println(s"I'm drummer and I play '$song'")
  }
}

object FactoryCreator {
  def getFactory(config: Boolean): MusicianAbstractFactory =
    if (config) {
      new DrummerFactory
    } else {
      new GuitarPlayerFactory
    }
}
// interfaces to import
trait Musician {
  def play(song: String)
}

trait MusicianAbstractFactory {
  def create(): Musician
}
import implementation.FactoryCreator

object AbstractFactoryTest {
  def readFromConfig(): Boolean = true

  def main(args: Array[String]) {
    val factory = FactoryCreator.getFactory(readFromConfig())
    val musician = factory.create()
    musician.play("Highway to hell")
  }
}
Python 实现
from abc import ABC, abstractmethod
from sys import platform


class Button(ABC):
    @abstractmethod
    def paint(self):
        pass


class LinuxButton(Button):
    def paint(self):
        return "Render a button in a Linux style"


class WindowsButton(Button):
    def paint(self):
        return "Render a button in a Windows style"


class MacOSButton(Button):
    def paint(self):
        return "Render a button in a MacOS style"


class GUIFactory(ABC):
    @abstractmethod
    def create_button(self):
        pass


class LinuxFactory(GUIFactory):
    def create_button(self):
        return LinuxButton()


class WindowsFactory(GUIFactory):
    def create_button(self):
        return WindowsButton()


class MacOSFactory(GUIFactory):
    def create_button(self):
        return MacOSButton()


if platform == "linux":
    factory = LinuxFactory()
elif platform == "darwin":
    factory = MacOSFactory()
elif platform == "win32":
    factory = WindowsFactory()
else:
    raise NotImplementedError(f"Not implemented for your platform: {platform}")

button = factory.create_button()
result = button.paint()
print(result)

使用类本身作为工厂的另一种实现

from abc import ABC, abstractmethod
from sys import platform


class Button(ABC):
    @abstractmethod
    def paint(self):
        pass


class LinuxButton(Button):
    def paint(self):
        return "Render a button in a Linux style"


class WindowsButton(Button):
    def paint(self):
        return "Render a button in a Windows style"


class MacOSButton(Button):
    def paint(self):
        return "Render a button in a MacOS style"


if platform == "linux":
    factory = LinuxButton
elif platform == "darwin":
    factory = MacOSButton
elif platform == "win32":
    factory = WindowsButton
else:
    raise NotImplementedError(f"Not implemented for your platform: {platform}")

button = factory()
result = button.paint()
print(result)

另一个例子

import platform

class GuiFactory():
    """Abstract Factory"""
    
    @classmethod
    def getFactory(Class):
        if platform.system() == "Windows":
            return WinFactory()
        elif platform.system() == "OSX":
            return OSXFactory()
        elif platform.system() == "Linux":
            return LinuxFactory()
    
    class Button:
        """ Abstract Product"""
        def paint(self):
            raise NotImplementedError
            
    @classmethod
    def getButton(Class):
        return Class.Button()

class WinFactory(GuiFactory):
    """Concrete Factory"""
    
    class Button(GuiFactory.Button):
        """Concrete Product"""
        def paint(self):
            print "I am a Windows button"

class LinuxFactory(GuiFactory):
    """Concrete Factory"""
    
    class Button(GuiFactory.Button):
        """Concrete Product"""
        def paint(self):
            print "I am a Linux button"

class OSXFactory(GuiFactory):
    """Concrete Factory"""
    
    class Button(GuiFactory.Button):
        """Concrete Product"""
        def paint(self):
            print "I am a OSX button"
            
def main():
    """Application"""
    factory = GuiFactory.getFactory()
    factory.getButton().paint()
    
if __name__ == "__main__":
    main()
Delphi 实现
program AbstractFactory;

{$APPTYPE CONSOLE}
{$R *.res}

uses
  System.SysUtils;

type
  (* abstract factory *)
  TAbstractFactory = class abstract
    procedure Paint(); virtual; abstract;
  end;

  (* abstract product *)
  TGUIFactory = class abstract
    function CreateButton(): TAbstractFactory; virtual; abstract;
  end;

  (* concrete product *)
  TOSXButton = class(TAbstractFactory)
  public
    procedure Paint(); override;
  end;

  (* concrete product *)
  TWinButton = class(TAbstractFactory)
  public
    procedure Paint(); override;
  end;

  (* concrete factory *)
  TOSXFactory = class(TGUIFactory)
  public
    function CreateButton(): TAbstractFactory; override;
  end;

  (* concrete factory *)
  TWinFactory = class(TGUIFactory)
  public
    function CreateButton(): TAbstractFactory; override;
  end;

  (* client *)
  TApplication = class
  public
    constructor Create(factory: TGUIFactory);
  end;

  (* Just for OOP style use class. This function is to return button factory only. *)
  TApplicationRunner = class
  public
    class function CreateOsSpecificFactory: TGUIFactory;
  end;

{ TOSXButton }
procedure TOSXButton.Paint;
begin
  WriteLn('I`m an OSXButton');
end;

{ TWinButton }
procedure TWinButton.Paint;
begin
  WriteLn('I`m a WinButton');
end;

{ TOSXFactory }
function TOSXFactory.CreateButton: TAbstractFactory;
begin
  Result := TOSXButton.Create;
end;

{ TWinFactory }
function TWinFactory.CreateButton: TAbstractFactory;
begin
  Result := TWinButton.Create;
end;

{ TApplication }
constructor TApplication.Create(factory: TGUIFactory);
var
  button: TAbstractFactory;
begin
  button := factory.CreateButton;
  button.Paint;
end;

{ TApplicationRunner }
class function TApplicationRunner.CreateOsSpecificFactory: TGUIFactory;
var
  sysType: string;
begin
  WriteLn('Enter OS type (Win: Windows, OSX: MacOS X)');
  ReadLn(sysType);
  if (sysType = 'Win') then
    Result := TWinFactory.Create
  else
    Result := TOSXFactory.Create
end;

var
  App: TApplication;

begin
  try
    { TODO -oUser -cConsole Main : Insert code here }
    App := TApplication.Create(TApplicationRunner.CreateOsSpecificFactory);

    WriteLn(#13#10 + 'Press any key to continue...');
    ReadLn;

    App.Free;
  except
    on E: Exception do
      WriteLn(E.ClassName, ': ', E.Message);
  end;

end.


Clipboard

待办事项
添加更多使用示例。


计算机科学设计模式
抽象工厂
适配器


您对本页有任何疑问吗?
在此处提问


在此书上创建一个新页面


华夏公益教科书