工厂方法和抽象工厂设计模式有什么区别?

What is the difference between factory method and abstract factory design patterns?

工厂方法和抽象工厂设计模式有什么区别?我对两者都感到困惑。抽象工厂是否使用工厂方法来实现自身?

请举例说明。


一般来说,工厂模式源于这样一种思想:对象实例化是一件重要的事情,它不应该是分散的交叉代码,而是应该从一个集中的位置进行,以获得更多的控制;它也更整洁。

工厂方法只是为了达到上述目的

1
2
3
4
5
6
     ControlFactory
 {
  public Button GetButton(){return new Button();}
  public Label GetLabel(){return new Label();}
  public TextBox GetTextBox(){return new TextBox();}
 }

然后,为了实例化这些控件,您将在下面编写代码

1
2
3
4
ControlFactory cf=new ControlFactory();

Button b=cf.GetButton();b.Text="Click Me";
Label l=cf.GetLabel();

另一方面,抽象工厂有助于处理对象族。如果你为免费和付费用户计划不同版本的软件,你可以选择使用普通的免费版本控制和一些美学上更好的付费版本控制。这可以用抽象的工厂模式优雅地处理。

1
2
3
4
5
 abstract class ControlsFactory
 {
    public abstract Button GetButton();
    public abstract Label GetLabel();
 }

---现在FreeControlFactory和ExoticControlFactory继承了上面的类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
 class FreeControlsFactory:ControlsFactory
 {


  public override Button GetButton()
  {
      return new FreeButton();//Assume that **FreeControl** and **ExoticControl** are Inherited From **Control**
  }

  public override Label GetLabel()
  {
      return new FreeLabel();
  }

 }

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
 class ExoticControlsFactory : ControlsFactory
 {


  public override Button GetButton()
  {
   return new ExoticButton();
  }

  public override Label GetLabel()
  {
   return new ExoticLabel();
  }

 }

假设FreeControl和ExoticControl是从控件继承的(我不在这里编写代码)

现在,您将编写下面的代码以将所有控件切换到另一个版本。

1
2
3
4
if (VersionKey=="FreeVersion")
    {ControlFactory cf= new FreeControlFactory();}
ese if (VersionKey=="PaidVersion")
    {cf=new ExoticControlFactory();}

根据上述选择,所有位置控制将被切换。

1
2
3
4
5
Button b1=cf.GetButton();//b1 will be based on which family cf is containing
Button b2=cf.GetButton();
Button b3=cf.GetButton();
Label l1= cf.GetLabel();
Label l2= cf.GetLabel();

正是多态行为有助于此,即CF可以包含自由工厂或外显工厂。这就决定了要创建哪些控件。


工厂方法隐藏单个对象的构造;它可以用于实现虚拟构造函数。工厂方法的另一个特殊情况是原型模式中使用的"克隆"方法。工厂方法只是返回新对象的函数。

抽象工厂隐藏了相关对象族的构造。抽象工厂通常使用(一组)工厂方法来实现。例如,假设您想使您的GUI实现独立于任何特定的工具箱。您可能决定为不同的控件创建抽象类,以及创建控件的抽象工厂:

1
2
3
4
5
6
7
8
9
10
11
class Button { };
class Label { };
class CheckBox { };

class Toolkit {
public:
    virtual ~Toolkit() {}
    virtual Button *createButton() = 0;
    virtual CheckBox *createCheckBox() = 0;
    virtual Label *createLabel() = 0;
};

然后,您可以实现抽象工具箱类以及每个工具箱的抽象控制类,例如:

1
2
3
4
5
6
7
8
9
10
11
class QtButton : public Button { };
class QtLabel : public Button { };
class QtCheckBox : public Button { };

class QtToolkit {
public:
    virtual ~Toolkit() {}
    virtual Button *createButton() { return new QtButton; }
    virtual CheckBox *createCheckBox() { return new QtCheckBox; }
    virtual Label *createLabel() { return new QtLabel; }
};

实际构造GUI的代码只需要一个Toolkit*,因此耦合度非常低:

1
2
3
4
5
6
7
void constructGUI( Toolkit *tk )
{
   Button *okButton = tk->createButton();
   okButton->setText("OK" );

   // ...
}

这将使用一组相关对象(在本例中是GUI控件)将客户机与控件的实现分离。


例如,使用工厂模式直接创建子类

1
2
3
4
5
6
7
class CatFactory
{
    ICat Create(string name);
}

CatFactory = new CatFactory();
ICat myCat = myCatFactory.Create("Lion")

抽象工厂通过定义工厂必须实现的接口(例如ICatFactory)来进一步了解这一点,该接口将您从使用特定工厂类中分离出来。

1
2
3
4
interface ICatFactory
{
    ICat Create(string name);
}

如何创建抽象工厂的实例?工厂工厂可能是概念上理解的最简单的方法,但实际上最简单的方法(取决于应用程序的规模)可能是使用依赖注入框架,该框架为解耦类提供了许多辅助功能。

1
2
ICatFactory = DependencyInjector.Get<ICatFactory>();
ICat myCat = myCatFactory.Create("Lion")

或者仅仅取决于框架

1
ICat myCat = DependencyInjector.Get<ICat>("Lion")