// 具体工厂可生成属于同一变体的系列产品。工厂会确保其创建的产品能相互搭配 // 使用。具体工厂方法签名会返回一个抽象产品,但在方法内部则会对具体产品进 // 行实例化。 class WinFactory implements GUIFactory is method createButton():Button is return new WinButton() method createCheckbox():Checkbox is return new WinCheckbox()
// 每个具体工厂中都会包含一个相应的产品变体。 class MacFactory implements GUIFactory is method createButton():Button is return new MacButton() method createCheckbox():Checkbox is return new MacCheckbox()
// 系列产品中的特定产品必须有一个基础接口。所有产品变体都必须实现这个接口。 interface Button is method paint()
// 具体产品由相应的具体工厂创建。 class WinButton implements Button is method paint() is // 根据 Windows 样式渲染按钮。
class MacButton implements Button is method paint() is // 根据 macOS 样式渲染按钮
// 这是另一个产品的基础接口。所有产品都可以互动,但是只有相同具体变体的产 // 品之间才能够正确地进行交互。 interface Checkbox is method paint()
class WinCheckbox implements Checkbox is method paint() is // 根据 Windows 样式渲染复选框。
class MacCheckbox implements Checkbox is method paint() is // 根据 macOS 样式渲染复选框。
namespaceRefactoringGuru.DesignPatterns.AbstractFactory.Conceptual { // The Abstract Factory interface declares a set of methods that return // different abstract products. These products are called a family and are // related by a high-level theme or concept. Products of one family are // usually able to collaborate among themselves. A family of products may // have several variants, but the products of one variant are incompatible // with products of another. publicinterfaceIAbstractFactory { IAbstractProductA CreateProductA();
IAbstractProductB CreateProductB(); }
// Concrete Factories produce a family of products that belong to a single // variant. The factory guarantees that resulting products are compatible. // Note that signatures of the Concrete Factory's methods return an abstract // product, while inside the method a concrete product is instantiated. classConcreteFactory1 : IAbstractFactory { public IAbstractProductA CreateProductA() { returnnew ConcreteProductA1(); }
public IAbstractProductB CreateProductB() { returnnew ConcreteProductB1(); } }
// Each Concrete Factory has a corresponding product variant. classConcreteFactory2 : IAbstractFactory { public IAbstractProductA CreateProductA() { returnnew ConcreteProductA2(); }
public IAbstractProductB CreateProductB() { returnnew ConcreteProductB2(); } }
// Each distinct product of a product family should have a base interface. // All variants of the product must implement this interface. publicinterfaceIAbstractProductA { stringUsefulFunctionA(); }
// Concrete Products are created by corresponding Concrete Factories. classConcreteProductA1 : IAbstractProductA { publicstringUsefulFunctionA() { return"The result of the product A1."; } }
classConcreteProductA2 : IAbstractProductA { publicstringUsefulFunctionA() { return"The result of the product A2."; } }
// Here's the the base interface of another product. All products can // interact with each other, but proper interaction is possible only between // products of the same concrete variant. publicinterfaceIAbstractProductB { // Product B is able to do its own thing... stringUsefulFunctionB();
// ...but it also can collaborate with the ProductA. // // The Abstract Factory makes sure that all products it creates are of // the same variant and thus, compatible. stringAnotherUsefulFunctionB(IAbstractProductA collaborator); }
// Concrete Products are created by corresponding Concrete Factories. classConcreteProductB1 : IAbstractProductB { publicstringUsefulFunctionB() { return"The result of the product B1."; }
// The variant, Product B1, is only able to work correctly with the // variant, Product A1. Nevertheless, it accepts any instance of // AbstractProductA as an argument. publicstringAnotherUsefulFunctionB(IAbstractProductA collaborator) { var result = collaborator.UsefulFunctionA();
return$"The result of the B1 collaborating with the ({result})"; } }
classConcreteProductB2 : IAbstractProductB { publicstringUsefulFunctionB() { return"The result of the product B2."; }
// The variant, Product B2, is only able to work correctly with the // variant, Product A2. Nevertheless, it accepts any instance of // AbstractProductA as an argument. publicstringAnotherUsefulFunctionB(IAbstractProductA collaborator) { var result = collaborator.UsefulFunctionA();
return$"The result of the B2 collaborating with the ({result})"; } }
// The client code works with factories and products only through abstract // types: AbstractFactory and AbstractProduct. This lets you pass any // factory or product subclass to the client code without breaking it. classClient { publicvoidMain() { // The client code can work with any concrete factory class. Console.WriteLine("Client: Testing client code with the first factory type..."); ClientMethod(new ConcreteFactory1()); Console.WriteLine();
Console.WriteLine("Client: Testing the same client code with the second factory type..."); ClientMethod(new ConcreteFactory2()); }
publicvoidClientMethod(IAbstractFactory factory) { var productA = factory.CreateProductA(); var productB = factory.CreateProductB();
classProgram { staticvoidMain(string[] args) { new Client().Main(); } } }
Output.txt: 执行结果
1 2 3 4 5 6 7
Client: Testing client code with the first factory type... The result of the product B1. The result of the B1 collaborating with the (The result of the product A1.)
Client: Testing the same client code with the second factory type... The result of the product B2. The result of the B2 collaborating with the (The result of the product A2.)
在 C++ 中使用模式
复杂度: ★★☆
流行度: ★★★
使用示例: 抽象工厂模式在 C++ 代码中很常见。 许多框架和程序库会将它作为扩展和自定义其标准组件的一种方式。
/** * Each distinct product of a product family should have a base interface. All * variants of the product must implement this interface. */ classAbstractProductA { public: virtual ~AbstractProductA(){}; virtual std::string UsefulFunctionA()const= 0; };
/** * Concrete Products are created by corresponding Concrete Factories. */ classConcreteProductA1 : public AbstractProductA { public: std::string UsefulFunctionA()constoverride{ return"The result of the product A1."; } };
classConcreteProductA2 : public AbstractProductA { std::string UsefulFunctionA()constoverride{ return"The result of the product A2."; } };
/** * Here's the the base interface of another product. All products can interact * with each other, but proper interaction is possible only between products of * the same concrete variant. */ classAbstractProductB { /** * Product B is able to do its own thing... */ public: virtual ~AbstractProductB(){}; virtual std::string UsefulFunctionB()const= 0; /** * ...but it also can collaborate with the ProductA. * * The Abstract Factory makes sure that all products it creates are of the * same variant and thus, compatible. */ virtual std::string AnotherUsefulFunctionB(const AbstractProductA &collaborator)const= 0; };
/** * Concrete Products are created by corresponding Concrete Factories. */ classConcreteProductB1 : public AbstractProductB { public: std::string UsefulFunctionB()constoverride{ return"The result of the product B1."; } /** * The variant, Product B1, is only able to work correctly with the variant, * Product A1. Nevertheless, it accepts any instance of AbstractProductA as an * argument. */ std::string AnotherUsefulFunctionB(const AbstractProductA &collaborator)constoverride{ const std::string result = collaborator.UsefulFunctionA(); return"The result of the B1 collaborating with ( " + result + " )"; } };
classConcreteProductB2 : public AbstractProductB { public: std::string UsefulFunctionB()constoverride{ return"The result of the product B2."; } /** * The variant, Product B2, is only able to work correctly with the variant, * Product A2. Nevertheless, it accepts any instance of AbstractProductA as an * argument. */ std::string AnotherUsefulFunctionB(const AbstractProductA &collaborator)constoverride{ const std::string result = collaborator.UsefulFunctionA(); return"The result of the B2 collaborating with ( " + result + " )"; } };
/** * The Abstract Factory interface declares a set of methods that return * different abstract products. These products are called a family and are * related by a high-level theme or concept. Products of one family are usually * able to collaborate among themselves. A family of products may have several * variants, but the products of one variant are incompatible with products of * another. */ classAbstractFactory { public: virtual AbstractProductA *CreateProductA()const= 0; virtual AbstractProductB *CreateProductB()const= 0; };
/** * Concrete Factories produce a family of products that belong to a single * variant. The factory guarantees that resulting products are compatible. Note * that signatures of the Concrete Factory's methods return an abstract product, * while inside the method a concrete product is instantiated. */ classConcreteFactory1 : public AbstractFactory { public: AbstractProductA *CreateProductA()constoverride{ returnnewConcreteProductA1(); } AbstractProductB *CreateProductB()constoverride{ returnnewConcreteProductB1(); } };
/** * Each Concrete Factory has a corresponding product variant. */ classConcreteFactory2 : public AbstractFactory { public: AbstractProductA *CreateProductA()constoverride{ returnnewConcreteProductA2(); } AbstractProductB *CreateProductB()constoverride{ returnnewConcreteProductB2(); } };
/** * The client code works with factories and products only through abstract * types: AbstractFactory and AbstractProduct. This lets you pass any factory or * product subclass to the client code without breaking it. */
intmain(){ std::cout << "Client: Testing client code with the first factory type:\n"; ConcreteFactory1 *f1 = newConcreteFactory1(); ClientCode(*f1); delete f1; std::cout << std::endl; std::cout << "Client: Testing the same client code with the second factory type:\n"; ConcreteFactory2 *f2 = newConcreteFactory2(); ClientCode(*f2); delete f2; return0; }
Output.txt: 执行结果
1 2 3 4 5 6 7
Client: Testing client code with the first factory type: The result of the product B1. The result of the B1 collaborating with the (The result of the product A1.)
Client: Testing the same client code with the second factory type: The result of the product B2. The result of the B2 collaborating with the (The result of the product A2.)
/** * Abstract Factory assumes that you have several families of products, * structured into separate class hierarchies (Button/Checkbox). All products of * the same family have the common interface. * * This is the common interface for buttons family. */ publicinterfaceButton { voidpaint(); }
/** * All products families have the same varieties (MacOS/Windows). * * This is a MacOS variant of a button. */ publicclassMacOSButtonimplementsButton {
@Override publicvoidpaint() { System.out.println("You have created MacOSButton."); } }
/** * All products families have the same varieties (MacOS/Windows). * * This is another variant of a button. */ publicclassWindowsButtonimplementsButton {
@Override publicvoidpaint() { System.out.println("You have created WindowsButton."); } }
/** * All products families have the same varieties (MacOS/Windows). * * This is a variant of a checkbox. */ publicclassMacOSCheckboximplementsCheckbox {
@Override publicvoidpaint() { System.out.println("You have created MacOSCheckbox."); } }
/** * All products families have the same varieties (MacOS/Windows). * * This is another variant of a checkbox. */ publicclassWindowsCheckboximplementsCheckbox {
@Override publicvoidpaint() { System.out.println("You have created WindowsCheckbox."); } }
/** * Each concrete factory extends basic factory and responsible for creating * products of a single variety. */ publicclassMacOSFactoryimplementsGUIFactory {
@Override public Button createButton() { returnnewMacOSButton(); }
@Override public Checkbox createCheckbox() { returnnewMacOSCheckbox(); } }
/** * Each concrete factory extends basic factory and responsible for creating * products of a single variety. */ publicclassWindowsFactoryimplementsGUIFactory {
@Override public Button createButton() { returnnewWindowsButton(); }
@Override public Checkbox createCheckbox() { returnnewWindowsCheckbox(); } }
/** * Factory users don't care which concrete factory they use since they work with * factories and products through abstract interfaces. */ publicclassApplication { private Button button; private Checkbox checkbox;
/** * Demo class. Everything comes together here. */ publicclassDemo {
/** * Application picks the factory type and creates it in run time (usually at * initialization stage), depending on the configuration or environment * variables. */ privatestatic Application configureApplication() { Application app; GUIFactory factory; StringosName= System.getProperty("os.name").toLowerCase(); if (osName.contains("mac")) { factory = newMacOSFactory(); app = newApplication(factory); } else { factory = newWindowsFactory(); app = newApplication(factory); } return app; }
/** * The Abstract Factory interface declares a set of methods that return * different abstract products. These products are called a family and are * related by a high-level theme or concept. Products of one family are usually * able to collaborate among themselves. A family of products may have several * variants, but the products of one variant are incompatible with products of * another. */ interfaceAbstractFactory { publicfunctioncreateProductA(): AbstractProductA;
/** * Concrete Factories produce a family of products that belong to a single * variant. The factory guarantees that resulting products are compatible. Note * that signatures of the Concrete Factory's methods return an abstract product, * while inside the method a concrete product is instantiated. */ classConcreteFactory1implementsAbstractFactory { publicfunctioncreateProductA(): AbstractProductA { returnnewConcreteProductA1(); }
/** * Each distinct product of a product family should have a base interface. All * variants of the product must implement this interface. */ interfaceAbstractProductA { publicfunctionusefulFunctionA(): string; }
/** * Concrete Products are created by corresponding Concrete Factories. */ classConcreteProductA1implementsAbstractProductA { publicfunctionusefulFunctionA(): string { return"The result of the product A1."; } }
classConcreteProductA2implementsAbstractProductA { publicfunctionusefulFunctionA(): string { return"The result of the product A2."; } }
/** * Here's the the base interface of another product. All products can interact * with each other, but proper interaction is possible only between products of * the same concrete variant. */ interfaceAbstractProductB { /** * Product B is able to do its own thing... */ publicfunctionusefulFunctionB(): string;
/** * ...but it also can collaborate with the ProductA. * * The Abstract Factory makes sure that all products it creates are of the * same variant and thus, compatible. */ publicfunctionanotherUsefulFunctionB(AbstractProductA $collaborator): string; }
/** * Concrete Products are created by corresponding Concrete Factories. */ classConcreteProductB1implementsAbstractProductB { publicfunctionusefulFunctionB(): string { return"The result of the product B1."; }
/** * The variant, Product B1, is only able to work correctly with the variant, * Product A1. Nevertheless, it accepts any instance of AbstractProductA as * an argument. */ publicfunctionanotherUsefulFunctionB(AbstractProductA $collaborator): string { $result = $collaborator->usefulFunctionA();
return"The result of the B1 collaborating with the ({$result})"; } }
classConcreteProductB2implementsAbstractProductB { publicfunctionusefulFunctionB(): string { return"The result of the product B2."; }
/** * The variant, Product B2, is only able to work correctly with the variant, * Product A2. Nevertheless, it accepts any instance of AbstractProductA as * an argument. */ publicfunctionanotherUsefulFunctionB(AbstractProductA $collaborator): string { $result = $collaborator->usefulFunctionA();
return"The result of the B2 collaborating with the ({$result})"; } }
/** * The client code works with factories and products only through abstract * types: AbstractFactory and AbstractProduct. This lets you pass any factory or * product subclass to the client code without breaking it. */ functionclientCode(AbstractFactory $factory) { $productA = $factory->createProductA(); $productB = $factory->createProductB();
/** * The client code can work with any concrete factory class. */ echo"Client: Testing client code with the first factory type:\n"; clientCode(newConcreteFactory1());
echo"\n";
echo"Client: Testing the same client code with the second factory type:\n"; clientCode(newConcreteFactory2());
Output.txt: 执行结果
1 2 3 4 5 6 7
Client: Testing client code with the first factory type: The result of the product B1. The result of the B1 collaborating with the (The result of the product A1.)
Client: Testing the same client code with the second factory type: The result of the product B2. The result of the B2 collaborating with the (The result of the product A2.)
/** * Each distinct product type should have a separate interface. All variants of * the product must follow the same interface. * * For instance, this Abstract Product interface describes the behavior of page * title templates. */ interfaceTitleTemplate { publicfunctiongetTemplateString(): string; }
/** * This Concrete Product provides Twig page title templates. */ classTwigTitleTemplateimplementsTitleTemplate { publicfunctiongetTemplateString(): string { return"<h1>{{ title }}</h1>"; } }
/** * And this Concrete Product provides PHPTemplate page title templates. */ classPHPTemplateTitleTemplateimplementsTitleTemplate { publicfunctiongetTemplateString(): string { return"<h1><?= \$title; ?></h1>"; } }
/** * This is another Abstract Product type, which describes whole page templates. */ interfacePageTemplate { publicfunctiongetTemplateString(): string; }
/** * The page template uses the title sub-template, so we have to provide the way * to set it in the sub-template object. The abstract factory will link the page * template with a title template of the same variant. */ abstractclassBasePageTemplateimplementsPageTemplate { protected$titleTemplate;
/** * The renderer is responsible for converting a template string into the actual * HTML code. Each renderer behaves differently and expects its own type of * template strings passed to it. Baking templates with the factory let you pass * proper types of templates to proper renders. */ interfaceTemplateRenderer { publicfunctionrender(string$templateString, array$arguments = []): string; }
/** * The renderer for Twig templates. */ classTwigRendererimplementsTemplateRenderer { publicfunctionrender(string$templateString, array$arguments = []): string { return\Twig::render($templateString, $arguments); } }
/** * The renderer for PHPTemplate templates. Note that this implementation is very * basic, if not crude. Using the `eval` function has many security * implications, so use it with caution in real projects. */ classPHPTemplateRendererimplementsTemplateRenderer { publicfunctionrender(string$templateString, array$arguments = []): string { extract($arguments);
/** * The client code. Note that it accepts the Abstract Factory class as the * parameter, which allows the client to work with any concrete factory type. */ classPage {
// Here's how would you use the template further in real life. Note that the // page class does not depend on any concrete template classes. publicfunctionrender(TemplateFactory $factory): string { $pageTemplate = $factory->createPageTemplate();
/** * Now, in other parts of the app, the client code can accept factory objects of * any type. */ $page = newPage('Sample page', 'This it the body.');
echo"Testing actual rendering with the PHPTemplate factory:\n"; echo$page->render(newPHPTemplateFactory());
// Uncomment the following if you have Twig installed.
// echo "Testing rendering with the Twig factory:\n"; echo $page->render(new // TwigTemplateFactory());
Output.txt: 执行结果
1 2 3 4 5
Testing actual rendering with the PHPTemplate factory: <div class="page"> <h1>Sample page</h1> <article class="content">This it the body.</article> </div>
from __future__ import annotations from abc import ABC, abstractmethod
classAbstractFactory(ABC): """ The Abstract Factory interface declares a set of methods that return different abstract products. These products are called a family and are related by a high-level theme or concept. Products of one family are usually able to collaborate among themselves. A family of products may have several variants, but the products of one variant are incompatible with products of another. """ @abstractmethod defcreate_product_a(self) -> AbstractProductA: pass
classConcreteFactory1(AbstractFactory): """ Concrete Factories produce a family of products that belong to a single variant. The factory guarantees that resulting products are compatible. Note that signatures of the Concrete Factory's methods return an abstract product, while inside the method a concrete product is instantiated. """
classAbstractProductA(ABC): """ Each distinct product of a product family should have a base interface. All variants of the product must implement this interface. """
""" Concrete Products are created by corresponding Concrete Factories. """
classConcreteProductA1(AbstractProductA): defuseful_function_a(self) -> str: return"The result of the product A1."
classConcreteProductA2(AbstractProductA): defuseful_function_a(self) -> str: return"The result of the product A2."
classAbstractProductB(ABC): """ Here's the the base interface of another product. All products can interact with each other, but proper interaction is possible only between products of the same concrete variant. """ @abstractmethod defuseful_function_b(self) -> None: """ Product B is able to do its own thing... """ pass
@abstractmethod defanother_useful_function_b(self, collaborator: AbstractProductA) -> None: """ ...but it also can collaborate with the ProductA. The Abstract Factory makes sure that all products it creates are of the same variant and thus, compatible. """ pass
""" Concrete Products are created by corresponding Concrete Factories. """
classConcreteProductB1(AbstractProductB): defuseful_function_b(self) -> str: return"The result of the product B1."
""" The variant, Product B1, is only able to work correctly with the variant, Product A1. Nevertheless, it accepts any instance of AbstractProductA as an argument. """
defanother_useful_function_b(self, collaborator: AbstractProductA) -> str: result = collaborator.useful_function_a() returnf"The result of the B1 collaborating with the ({result})"
classConcreteProductB2(AbstractProductB): defuseful_function_b(self) -> str: return"The result of the product B2."
defanother_useful_function_b(self, collaborator: AbstractProductA): """ The variant, Product B2, is only able to work correctly with the variant, Product A2. Nevertheless, it accepts any instance of AbstractProductA as an argument. """ result = collaborator.useful_function_a() returnf"The result of the B2 collaborating with the ({result})"
defclient_code(factory: AbstractFactory) -> None: """ The client code works with factories and products only through abstract types: AbstractFactory and AbstractProduct. This lets you pass any factory or product subclass to the client code without breaking it. """ product_a = factory.create_product_a() product_b = factory.create_product_b()
if __name__ == "__main__": """ The client code can work with any concrete factory class. """ print("Client: Testing client code with the first factory type:") client_code(ConcreteFactory1())
print("\n")
print("Client: Testing the same client code with the second factory type:") client_code(ConcreteFactory2())
Output.txt: 执行结果
1 2 3 4 5 6 7
Client: Testing client code with the first factory type: The result of the product B1. The result of the B1 collaborating with the (The result of the product A1.)
Client: Testing the same client code with the second factory type: The result of the product B2. The result of the B2 collaborating with the (The result of the product A2.)
# The Abstract Factory interface declares a set of methods that return different # abstract products. These products are called a family and are related by a # high-level theme or concept. Products of one family are usually able to # collaborate among themselves. A family of products may have several variants, # but the products of one variant are incompatible with products of another. classAbstractFactory # @abstract defcreate_product_a raise NotImplementedError, "#{self.class} has not implemented method '#{__method__}'" end
# @abstract defcreate_product_b raise NotImplementedError, "#{self.class} has not implemented method '#{__method__}'" end end
# Concrete Factories produce a family of products that belong to a single # variant. The factory guarantees that resulting products are compatible. Note # that signatures of the Concrete Factory's methods return an abstract product, # while inside the method a concrete product is instantiated. classConcreteFactory1 < AbstractFactory defcreate_product_a ConcreteProductA1.new end
defcreate_product_b ConcreteProductB1.new end end
# Each Concrete Factory has a corresponding product variant. classConcreteFactory2 < AbstractFactory defcreate_product_a ConcreteProductA2.new end
defcreate_product_b ConcreteProductB2.new end end
# Each distinct product of a product family should have a base interface. All # variants of the product must implement this interface. classAbstractProductA # @abstract # # @return [String] defuseful_function_a raise NotImplementedError, "#{self.class} has not implemented method '#{__method__}'" end end
# Concrete Products are created by corresponding Concrete Factories. classConcreteProductA1 < AbstractProductA defuseful_function_a 'The result of the product A1.' end end
classConcreteProductA2 < AbstractProductA defuseful_function_a 'The result of the product A2.' end end
# Here's the the base interface of another product. All products can interact # with each other, but proper interaction is possible only between products of # the same concrete variant. classAbstractProductB # Product B is able to do its own thing... defuseful_function_b raise NotImplementedError, "#{self.class} has not implemented method '#{__method__}'" end
# ...but it also can collaborate with the ProductA. # # The Abstract Factory makes sure that all products it creates are of the same # variant and thus, compatible. defanother_useful_function_b(_collaborator) raise NotImplementedError, "#{self.class} has not implemented method '#{__method__}'" end end
# Concrete Products are created by corresponding Concrete Factories. classConcreteProductB1 < AbstractProductB # @return [String] defuseful_function_b 'The result of the product B1.' end
# The variant, Product B1, is only able to work correctly with the variant, # Product A1. Nevertheless, it accepts any instance of AbstractProductA as an # argument. defanother_useful_function_b(collaborator) result = collaborator.useful_function_a "The result of the B1 collaborating with the (#{result})" end end
classConcreteProductB2 < AbstractProductB # @return [String] defuseful_function_b 'The result of the product B2.' end
# The variant, Product B2, is only able to work correctly with the variant, # Product A2. Nevertheless, it accepts any instance of AbstractProductA as an # argument. defanother_useful_function_b(collaborator) result = collaborator.useful_function_a "The result of the B2 collaborating with the (#{result})" end end
# The client code works with factories and products only through abstract types: # AbstractFactory and AbstractProduct. This lets you pass any factory or product # subclass to the client code without breaking it. defclient_code(factory) product_a = factory.create_product_a product_b = factory.create_product_b
puts product_b.useful_function_b.to_s puts product_b.another_useful_function_b(product_a).to_s end
# The client code can work with any concrete factory class. puts 'Client: Testing client code with the first factory type:' client_code(ConcreteFactory1.new)
puts "\n"
puts 'Client: Testing the same client code with the second factory type:' client_code(ConcreteFactory2.new)
output.txt: 执行结果
1 2 3 4 5 6 7
Client: Testing client code with the first factory type: The result of the product B1. The result of the B1 collaborating with the (The result of the product A1.)
Client: Testing the same client code with the second factory type: The result of the product B2. The result of the B2 collaborating with the (The result of the product A2.)
在 Swift 中使用模式
复杂度: ★★☆
流行度: ★★★
使用示例: 抽象工厂模式在 Swift 代码中很常见。 许多框架和程序库会将它作为扩展和自定义其标准组件的一种方式。
/// The Abstract Factory protocol declares a set of methods that return /// different abstract products. These products are called a family and are /// related by a high-level theme or concept. Products of one family are usually /// able to collaborate among themselves. A family of products may have several /// variants, but the products of one variant are incompatible with products of /// another. protocolAbstractFactory {
/// Concrete Factories produce a family of products that belong to a single /// variant. The factory guarantees that resulting products are compatible. Note /// that signatures of the Concrete Factory's methods return an abstract /// product, while inside the method a concrete product is instantiated. classConcreteFactory1: AbstractFactory {
/// Each distinct product of a product family should have a base protocol. All /// variants of the product must implement this protocol. protocolAbstractProductA {
funcusefulFunctionA() -> String }
/// Concrete Products are created by corresponding Concrete Factories. classConcreteProductA1: AbstractProductA {
funcusefulFunctionA() -> String { return"The result of the product A1." } }
classConcreteProductA2: AbstractProductA {
funcusefulFunctionA() -> String { return"The result of the product A2." } }
/// The base protocol of another product. All products can interact with each /// other, but proper interaction is possible only between products of the same /// concrete variant. protocolAbstractProductB {
/// Product B is able to do its own thing... funcusefulFunctionB() -> String
/// ...but it also can collaborate with the ProductA. /// /// The Abstract Factory makes sure that all products it creates are of the /// same variant and thus, compatible. funcanotherUsefulFunctionB(collaborator: AbstractProductA) -> String }
/// Concrete Products are created by corresponding Concrete Factories. classConcreteProductB1: AbstractProductB {
funcusefulFunctionB() -> String { return"The result of the product B1." }
/// This variant, Product B1, is only able to work correctly with the /// variant, Product A1. Nevertheless, it accepts any instance of /// AbstractProductA as an argument. funcanotherUsefulFunctionB(collaborator: AbstractProductA) -> String { let result = collaborator.usefulFunctionA() return"The result of the B1 collaborating with the (\(result))" } }
classConcreteProductB2: AbstractProductB {
funcusefulFunctionB() -> String { return"The result of the product B2." }
/// This variant, Product B2, is only able to work correctly with the /// variant, Product A2. Nevertheless, it accepts any instance of /// AbstractProductA as an argument. funcanotherUsefulFunctionB(collaborator: AbstractProductA) -> String { let result = collaborator.usefulFunctionA() return"The result of the B2 collaborating with the (\(result))" } }
/// The client code works with factories and products only through abstract /// types: AbstractFactory and AbstractProduct. This lets you pass any factory /// or product subclass to the client code without breaking it. classClient { // ... staticfuncsomeClientCode(factory: AbstractFactory) { let productA = factory.createProductA() let productB = factory.createProductB()
/// Let's see how it all works together. classAbstractFactoryConceptual: XCTestCase {
functestAbstractFactoryConceptual() {
/// The client code can work with any concrete factory class.
print("Client: Testing client code with the first factory type:") Client.someClientCode(factory: ConcreteFactory1())
print("Client: Testing the same client code with the second factory type:") Client.someClientCode(factory: ConcreteFactory2()) } }
Output.txt: 执行结果
1 2 3 4 5 6
Client: Testing client code with the first factory type: The result of the product B1. The result of the B1 collaborating with the (The result of the product A1.) Client: Testing the same client code with the second factory type: The result of the product B2. The result of the B2 collaborating with the (The result of the product A2.)
staticfuncauthView(fortype: AuthType) -> AuthView { print("Student View has been created") switch type { case .login: returnStudentLoginView() case .signUp: returnStudentSignUpView() } }
staticfuncauthController(fortype: AuthType) -> AuthViewController { let controller =StudentAuthViewController(contentView: authView(for: type)) print("Student View Controller has been created") return controller } }
classTeacherAuthViewFactory: AuthViewFactory {
staticfuncauthView(fortype: AuthType) -> AuthView { print("Teacher View has been created") switch type { case .login: returnTeacherLoginView() case .signUp: returnTeacherSignUpView() } }
staticfuncauthController(fortype: AuthType) -> AuthViewController { let controller =TeacherAuthViewController(contentView: authView(for: type)) print("Teacher View Controller has been created") return controller } }
protocolAuthView {
typealiasAuthAction= (AuthType) -> ()
var contentView: UIView { get } var authHandler: AuthAction? { getset }
var description: String { get } }
classStudentSignUpView: UIView, AuthView {
privateclassStudentSignUpContentView: UIView {
/// This view contains a number of features available only during a /// STUDENT authorization. }
var contentView: UIView=StudentSignUpContentView()
/// The handler will be connected for actions of buttons of this view. var authHandler: AuthView.AuthAction?
#if teacherMode let clientCode =ClientCode(factoryType: TeacherAuthViewFactory.self) #else let clientCode =ClientCode(factoryType: StudentAuthViewFactory.self) #endif
/// Present LogIn flow clientCode.presentLogin() print("Login screen has been presented")
/// Present SignUp flow clientCode.presentSignUp() print("Sign up screen has been presented") } }
Output.txt: 执行结果
1 2 3 4 5 6
Teacher View has been created Teacher View Controller has been created Login screen has been presented Teacher View has been created Teacher View Controller has been created Sign up screen has been presented
/** * The Abstract Factory interface declares a set of methods that return * different abstract products. These products are called a family and are * related by a high-level theme or concept. Products of one family are usually * able to collaborate among themselves. A family of products may have several * variants, but the products of one variant are incompatible with products of * another. */ interfaceAbstractFactory { createProductA(): AbstractProductA;
createProductB(): AbstractProductB; }
/** * Concrete Factories produce a family of products that belong to a single * variant. The factory guarantees that resulting products are compatible. Note * that signatures of the Concrete Factory's methods return an abstract product, * while inside the method a concrete product is instantiated. */ classConcreteFactory1implementsAbstractFactory { publiccreateProductA(): AbstractProductA { returnnewConcreteProductA1(); }
/** * Each distinct product of a product family should have a base interface. All * variants of the product must implement this interface. */ interfaceAbstractProductA { usefulFunctionA(): string; }
/** * These Concrete Products are created by corresponding Concrete Factories. */ classConcreteProductA1implementsAbstractProductA { publicusefulFunctionA(): string { return'The result of the product A1.'; } }
classConcreteProductA2implementsAbstractProductA { publicusefulFunctionA(): string { return'The result of the product A2.'; } }
/** * Here's the the base interface of another product. All products can interact * with each other, but proper interaction is possible only between products of * the same concrete variant. */ interfaceAbstractProductB { /** * Product B is able to do its own thing... */ usefulFunctionB(): string;
/** * ...but it also can collaborate with the ProductA. * * The Abstract Factory makes sure that all products it creates are of the * same variant and thus, compatible. */ anotherUsefulFunctionB(collaborator: AbstractProductA): string; }
/** * These Concrete Products are created by corresponding Concrete Factories. */ classConcreteProductB1implementsAbstractProductB {
publicusefulFunctionB(): string { return'The result of the product B1.'; }
/** * The variant, Product B1, is only able to work correctly with the variant, * Product A1. Nevertheless, it accepts any instance of AbstractProductA as * an argument. */ publicanotherUsefulFunctionB(collaborator: AbstractProductA): string { const result = collaborator.usefulFunctionA(); return`The result of the B1 collaborating with the (${result})`; } }
publicusefulFunctionB(): string { return'The result of the product B2.'; }
/** * The variant, Product B2, is only able to work correctly with the variant, * Product A2. Nevertheless, it accepts any instance of AbstractProductA as * an argument. */ publicanotherUsefulFunctionB(collaborator: AbstractProductA): string { const result = collaborator.usefulFunctionA(); return`The result of the B2 collaborating with the (${result})`; } }
/** * The client code works with factories and products only through abstract * types: AbstractFactory and AbstractProduct. This lets you pass any factory or * product subclass to the client code without breaking it. */ functionclientCode(factory: AbstractFactory) { const productA = factory.createProductA(); const productB = factory.createProductB();
/** * The client code can work with any concrete factory class. */ console.log('Client: Testing client code with the first factory type...'); clientCode(newConcreteFactory1());
console.log('');
console.log('Client: Testing the same client code with the second factory type...'); clientCode(newConcreteFactory2());
Output.txt: 执行结果
1 2 3 4 5 6 7
Client: Testing client code with the first factory type... The result of the product B1. The result of the B1 collaborating with the (The result of the product A1.)
Client: Testing the same client code with the second factory type... The result of the product B2. The result of the B2 collaborating with the (The result of the product A2.)