Design patterns 工厂模式中组件之间的依赖关系

Design patterns 工厂模式中组件之间的依赖关系,design-patterns,Design Patterns,谢谢你抽出时间 这是一个让我很困惑的问题!这是关于工厂模式中组件之间的依赖关系 原始模型 就像上面的图片一样,我们这里有一个窗户工厂模型 1.接口:IFatory iWindows、IButton、ITextBox(型号定义) 2.实现:WindowsFactory、MacFatory(实现接口) 新型 现在,我们已经改变了旧的模式。因此iWindows有两个属性,分别是“CloseButton”和“TitileBox”。问题出现了: 1.何时以及如何实现这两个属性 2.这两个属性应该与

谢谢你抽出时间

这是一个让我很困惑的问题!这是关于工厂模式中组件之间的依赖关系


原始模型

就像上面的图片一样,我们这里有一个窗户工厂模型

1.接口:IFatory iWindows、IButton、ITextBox(型号定义)

2.实现:WindowsFactory、MacFatory(实现接口)


新型

现在,我们已经改变了旧的模式。因此iWindows有两个属性,分别是“CloseButton”和“TitileBox”。问题出现了:

1.何时以及如何实现这两个属性

2.这两个属性应该与它们的容器窗口具有相同的样式,这意味着我们只能有WindowsStyle(窗口/按钮/文本框)或MacStyle(窗口/按钮/文本框)。禁止混合


为了解决这些问题,我做了一些尝试。请检查下面的代码

解决方案1 正如你所看到的,这个解决方案并不好

1.MacWindow类必须依赖于特定的IButton/ITextBox实现(尽管它们在同一工厂)。感觉很糟糕

2.如果有一天,我们从MacWindow类派生出一个新类,我们必须重写这些虚拟方法,使它们保持相同的样式


解决方案2 这个看起来更好,但现在非常完美

1.现在的工作容易多了,如果我们从MacFactory派生出一个名为MacOSXFactory的新工厂,我们只需要重写IFactory.MakeButton()和IFactory.MakeTextBox()方法;(呃..这些方法应该定义为“公共虚拟”)

2.对特定实现的依赖不再存在,但窗口类必须注入对IFactory的依赖。让一个产品知道工厂的细节感觉不好


这就是谜题! 哪种解决方案更好? 还有什么别的办法可以解决这个问题吗?(渴望知道!真的谢谢!) 你能给我一些建议吗

致谢
请允许我说“非常感谢!”感谢你抽出时间来阅读这个问题

您应该在工厂内实例化它们

解决方案1不够好,因为实例化业务应该在一个地方实现,而这个地方在工厂内。在每个工厂中已经有MakeButton和MakeTextBox实现,在MakeWindow实现中调用它们,如下所示

IWindow MakeWindow() //MacFactory's MakeWindow
{
    IWindow window = new MacWindow();
    window.TitleBox = this.MakeTextBox();
    window.CloseButton = this.MakeButton();
}
关于,文本框和按钮的创建应在工厂进行,因为工厂的责任是使用适当的业务规则创建对象


解决方案2还不够好,因为窗口不应该知道工厂的情况。或者窗口与其创建者没有任何关系,其任务是在屏幕上绘制窗口等()

您应该使用解决方案1

Class MacWindow必须依赖于特定的IButton/ITextBox实现(尽管它们在同一工厂)。

当您希望基于某些逻辑(在您的情况下是操作系统)创建通用初始化时,需要使用工厂。

当您创建一个
MacWindow
时,您已经知道它的所有组件都将始终是Mac的,所以您真的只需要使用工厂就可以了吗当然不是

我同意杰霍夫的意见,你的解决方案似乎太抽象了。它需要更多的约束来确保每个组件不会到达不同类型的窗口(MS到Mac,反之亦然)。我在这里使用术语
MSWindow
来区分

首先,我认为最好区分
MsComponent
MacComponent
,以防止错误的依赖注入。2接口
IMSCOComponent
IMacComponent
应足以满足此要求。对于泛型,以后两者都应该实现
IComponentBase
。由于无法定义{IMsComponent,ITextBox}等
多个实现
类型,因此需要第三个接口,即
IMsTextBox:IMsComponent,ITextBox
IMacTextBox:IMacComponent,ITextBox

所以图变成这样:

ITextBox  IComponentBase
    \           |  
     \     IMsComponent
      \        /    
      IMsTextBox
然后我们需要一个上下文来处理组件:

IWindowContext<TtextBox, Tbutton> where TtextBox : IComponentBase, ITextBox 
                                  where Tbutton : IComponentBase, IButton
{
    TtextBox TitleBox {get;set;}
    Tbutton CloseButton {get;set;}
}
对于工厂,您可以灵活地返回特定的windowContext或特定的窗口。但是,我更喜欢返回特定windowContext的工厂,因为它更灵活。别忘了让工厂也通用

public interface IContextFactory<TTextBox, TButton>
    where TTextBox : IComponent, ITextBox
    where TButton : IComponent, IButton
{
    IWindowContext<TTextBox, TButton> Create();
}
公共接口IContextFactory
其中TTextBox:IComponent,ITextBox
其中t按钮:IComponent,IButton
{
IWindowContext Create();
}

有点复杂吧?但是它可以确保
MsWindow
不能分配
MacComponent
。然而,如果可以的话,我认为你不需要这么抽象。如果你想要漏洞百出的抽象,你可以只使用Context和ContextFactory,而忘记所有的泛型。

好吧,我花了一段时间才理解潦草场景的意图。你添加了很多成分,所以我真的很难找到最好的钩子来回答你的问题

首先,您可以轻松地将Windows组件添加到Mac Windows中(前面已经说过),您创建了一套完整的重复类,这让我有点恼火,窗口实现似乎是一个非常具体的示例

所以,主要的问题是,你想要实现什么?首先,您不会摆脱依赖关系,而且依赖关系也不是一件坏事。此外,工厂应该让你的生活更轻松,而不是更艰难——在你需要的地方使用它们,而不是在任何地方

因此,具体的窗口实现依赖于具体的按钮和标题框实现。这意味着在您的情况下,窗口实现应该最了解它的子对象。工厂只创建窗口,窗口知道要创建哪些按钮。所以解决方案一看
IWindowContext<TtextBox, Tbutton> where TtextBox : IComponentBase, ITextBox 
                                  where Tbutton : IComponentBase, IButton
{
    TtextBox TitleBox {get;set;}
    Tbutton CloseButton {get;set;}
}
public class MsWindow{
   public MsWindow(IWindowContext<IMsTextBox, IMsButton> context){
       this.CloseButton = context.CloseButton;
       this.TitleTextBox = context.TitleTextBox;
   }

   public ITextBox TitleTextBox {get; private set;}
   public IButton CloseButton {get; private set;}
}
public interface IContextFactory<TTextBox, TButton>
    where TTextBox : IComponent, ITextBox
    where TButton : IComponent, IButton
{
    IWindowContext<TTextBox, TButton> Create();
}