Say I had a class that has a static factory method, like this:
假设我有一个具有静态工厂方法的类,如下所示:
public class Table
{
public static Table OpenTable(string path)
{
ITableFactory fac = IoC.Resolve<ITableFactory>();
return fac.OpenTable(path);
}
}
and a factory class that looks like this:
和一个看起来像这样的工厂类:
internal class TableFactory : ITableFactory
{
internal Table OpenTable(string path)
{
//Check the path
//Do some other stuff
//return a new Table.
}
}
Does this code smell bad to you?
这段代码对你来说味道不好吗?
EDIT: Another question: Is it a good idea to have a static method on the type that just forwards calls to the factory?
编辑:另一个问题:在只调用工厂调用的类型上有一个静态方法是一个好主意吗?
Some background: I used to have the TableFactory as public and make the user create a new one every time they needed to open a table but it felt like a long hall just to open a table. So I thought that I would make a static factory method on the Table class and make the factory class internal and just resolve it using IoC.
一些背景:我曾经将TableFactory作为公共场所,并让用户每次需要打开一张桌子时都会创建一个新的,但感觉就像打开桌子一样长的大厅。所以我认为我会在Table类上创建一个静态工厂方法,并使工厂类内部化,并使用IoC解决它。
4 个解决方案
#1
I don't think it's bad, per se, but perhaps a little unusual.
我认为这本身并不坏,但也许有点不寻常。
I would, however, present the table factory as a separate object to the user, and use that to create tables. Why ? It's a little more conventional, and it allows you the capability to be able to configure your factory in advance and use it for creating more than one table e.g.
但是,我会将表工厂作为单独的对象呈现给用户,并使用它来创建表。为什么?它更传统,它允许您能够提前配置工厂并使用它来创建多个表格,例如
TableFactory tf = new TableFactory();
tf.setWhatever();
tf.setWhatever2();
// ...etc...
// now create your tables based on the above.
Your code need not (necessarily) know anything about the table creation, other than the fact that it's been given a TableFactory
(built and configured elsewhere)
您的代码不需要(必然)了解有关表创建的任何信息,除了它已被赋予TableFactory(在其他地方构建和配置)的事实
That may be overkill for what you're doing. But I've found it's a useful pattern to follow.
对于你正在做的事情,这可能有点过头了。但我发现这是一个有用的模式。
#2
That looks fine. I would however move fac out:
看起来很好。然而,我会移出:
public class Table
{
private static readonly ITableFactory fac = IoC.Resolve<ITableFactory>();
public static Table OpenTable(string path)
{
return fac.OpenTable(path);
}
}
#3
I don't think this is too bad... it's just a shortcut method that introduces no new dependencies.
我不认为这太糟糕了......它只是一种不会引入新依赖关系的快捷方法。
I know in ninject you could possibly do Kernel.Get<Table>(path)
and avoid all this juggling.
我知道在ninject你可以做Kernel.Get
#4
As far as I can tell, what you have here is an instance of the Service Locator pattern, since I assume that IoC is a type name, and Resolve is a static method on the IoC type. Whether your TableFactory is internal or not is of less concern.
据我所知,这里有一个服务定位器模式的实例,因为我假设IoC是一个类型名称,而Resolve是IoC类型的静态方法。您的TableFactory是否内部是不太重要的。
I consider Service Locator to be an anti-pattern, since it is totally opaque to the user of the API which dependencies need to be in place; thus, one could easily invoke Table.OpenTable in a context where the call to IoC.Resolve would throw, and the API gives you absolutely no clue that this is the case. You also get no compile-time checking.
我认为Service Locator是一个反模式,因为它对API的用户完全不透明,需要依赖于它们;因此,可以在调用IoC.Resolve的上下文中轻松调用Table.OpenTable,并且API绝对不会让您知道这种情况。您也没有编译时检查。
I know Martin Fowler originally described the Service Locator pattern, so it's a pretty harsh thing to call it an anti-pattern, but I know I'm not alone in this. YMMV.
我知道Martin Fowler最初描述了Service Locator模式,所以将它称为反模式是一件相当苛刻的事情,但我知道我并不孤单。因人而异。
#1
I don't think it's bad, per se, but perhaps a little unusual.
我认为这本身并不坏,但也许有点不寻常。
I would, however, present the table factory as a separate object to the user, and use that to create tables. Why ? It's a little more conventional, and it allows you the capability to be able to configure your factory in advance and use it for creating more than one table e.g.
但是,我会将表工厂作为单独的对象呈现给用户,并使用它来创建表。为什么?它更传统,它允许您能够提前配置工厂并使用它来创建多个表格,例如
TableFactory tf = new TableFactory();
tf.setWhatever();
tf.setWhatever2();
// ...etc...
// now create your tables based on the above.
Your code need not (necessarily) know anything about the table creation, other than the fact that it's been given a TableFactory
(built and configured elsewhere)
您的代码不需要(必然)了解有关表创建的任何信息,除了它已被赋予TableFactory(在其他地方构建和配置)的事实
That may be overkill for what you're doing. But I've found it's a useful pattern to follow.
对于你正在做的事情,这可能有点过头了。但我发现这是一个有用的模式。
#2
That looks fine. I would however move fac out:
看起来很好。然而,我会移出:
public class Table
{
private static readonly ITableFactory fac = IoC.Resolve<ITableFactory>();
public static Table OpenTable(string path)
{
return fac.OpenTable(path);
}
}
#3
I don't think this is too bad... it's just a shortcut method that introduces no new dependencies.
我不认为这太糟糕了......它只是一种不会引入新依赖关系的快捷方法。
I know in ninject you could possibly do Kernel.Get<Table>(path)
and avoid all this juggling.
我知道在ninject你可以做Kernel.Get
#4
As far as I can tell, what you have here is an instance of the Service Locator pattern, since I assume that IoC is a type name, and Resolve is a static method on the IoC type. Whether your TableFactory is internal or not is of less concern.
据我所知,这里有一个服务定位器模式的实例,因为我假设IoC是一个类型名称,而Resolve是IoC类型的静态方法。您的TableFactory是否内部是不太重要的。
I consider Service Locator to be an anti-pattern, since it is totally opaque to the user of the API which dependencies need to be in place; thus, one could easily invoke Table.OpenTable in a context where the call to IoC.Resolve would throw, and the API gives you absolutely no clue that this is the case. You also get no compile-time checking.
我认为Service Locator是一个反模式,因为它对API的用户完全不透明,需要依赖于它们;因此,可以在调用IoC.Resolve的上下文中轻松调用Table.OpenTable,并且API绝对不会让您知道这种情况。您也没有编译时检查。
I know Martin Fowler originally described the Service Locator pattern, so it's a pretty harsh thing to call it an anti-pattern, but I know I'm not alone in this. YMMV.
我知道Martin Fowler最初描述了Service Locator模式,所以将它称为反模式是一件相当苛刻的事情,但我知道我并不孤单。因人而异。