C#中的工厂模式:如何确保对象实例只能由工厂类创建?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/515269/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Factory pattern in C#: How to ensure an object instance can only be created by a factory class?
提问by User
Recently I've been thinking about securing some of my code. I'm curious how one could make sure an object can never be created directly, but only via some method of a factory class. Let us say I have some "business object" class and I want to make sure any instance of this class will have a valid internal state. In order to achieve this I will need to perform some check before creating an object, probably in its constructor. This is all okay until I decide I want to make this check be a part of the business logic. So, how can I arrange for a business object to be creatable only through some method in my business logic class but never directly? The first natural desire to use a good old "friend" keyword of C++ will fall short with C#. So we need other options...
最近我一直在考虑保护我的一些代码。我很好奇如何确保永远不能直接创建对象,而只能通过工厂类的某种方法。假设我有一些“业务对象”类,我想确保此类的任何实例都具有有效的内部状态。为了实现这一点,我需要在创建对象之前执行一些检查,可能是在其构造函数中。这一切都很好,直到我决定要将此检查作为业务逻辑的一部分。那么,我怎样才能安排一个业务对象只能通过我的业务逻辑类中的某些方法而不是直接创建呢?使用 C++ 的老“朋友”关键字的第一个自然愿望与 C# 不符。所以我们需要其他选择......
Let's try some example:
让我们尝试一些例子:
public MyBusinessObjectClass
{
public string MyProperty { get; private set; }
public MyBusinessObjectClass (string myProperty)
{
MyProperty = myProperty;
}
}
public MyBusinessLogicClass
{
public MyBusinessObjectClass CreateBusinessObject (string myProperty)
{
// Perform some check on myProperty
if (true /* check is okay */)
return new MyBusinessObjectClass (myProperty);
return null;
}
}
It's all okay until you remember you can still create MyBusinessObjectClass instance directly, without checking the input. I would like to exclude that technical possibility altogether.
一切都好,直到您记得您仍然可以直接创建 MyBusinessObjectClass 实例,而无需检查输入。我想完全排除这种技术可能性。
So, what does the community think about this?
那么,社区对此有何看法?
采纳答案by Ricardo Nolde
Looks like you just want to run some business logic before creating the object - so why dont you just create a static method inside the "BusinessClass" that does all the dirty "myProperty" checking work, and make the constructor private?
看起来您只想在创建对象之前运行一些业务逻辑 - 那么为什么不在“BusinessClass”中创建一个静态方法来完成所有脏的“myProperty”检查工作,并将构造函数设为私有?
public BusinessClass
{
public string MyProperty { get; private set; }
private BusinessClass()
{
}
private BusinessClass(string myProperty)
{
MyProperty = myProperty;
}
public static BusinessClass CreateObject(string myProperty)
{
// Perform some check on myProperty
if (/* all ok */)
return new BusinessClass(myProperty);
return null;
}
}
Calling it would be pretty straightforward:
调用它会非常简单:
BusinessClass objBusiness = BusinessClass.CreateObject(someProperty);
回答by Matt Hamilton
You could make the constructor on your MyBusinessObjectClass class internal, and move it and the factory into their own assembly. Now only the factory should be able to construct an instance of the class.
您可以将 MyBusinessObjectClass 类的构造函数设为内部,并将其和工厂移动到它们自己的程序集中。现在只有工厂应该能够构造类的实例。
回答by Jon Skeet
You can make the constructor private, and the factory a nested type:
您可以将构造函数设为私有,并将工厂设为嵌套类型:
public class BusinessObject
{
private BusinessObject(string property)
{
}
public class Factory
{
public static BusinessObject CreateBusinessObject(string property)
{
return new BusinessObject(property);
}
}
}
This works because nested types have access to the private members of their enclosing types. I know it's a bit restrictive, but hopefully it'll help...
这是有效的,因为嵌套类型可以访问其封闭类型的私有成员。我知道这有点限制,但希望它会有所帮助......
回答by Fabian Schmied
Apart from what Jon suggested, you could also either have the factory method (including the check) be a static method of BusinessObject in the first place. Then, have the constructor private, and everyone else will be forced to use the static method.
除了 Jon 的建议之外,您还可以首先让工厂方法(包括检查)成为 BusinessObject 的静态方法。然后,将构造函数设为私有,其他所有人都将被迫使用静态方法。
public class BusinessObject
{
public static Create (string myProperty)
{
if (...)
return new BusinessObject (myProperty);
else
return null;
}
}
But the real question is - why do you have this requirement? Is it acceptable to move the factory or the factory method into the class?
但真正的问题是 - 为什么你有这个要求?将工厂或工厂方法移动到类中是否可以接受?
回答by Dan C.
Yet another (lightweight) option is to make a static factory method in the BusinessObject class and keep the constructor private.
另一个(轻量级)选项是在 BusinessObject 类中创建静态工厂方法并保持构造函数私有。
public class BusinessObject
{
public static BusinessObject NewBusinessObject(string property)
{
return new BusinessObject();
}
private BusinessObject()
{
}
}
回答by Fabian Schmied
Or, if you want to go really fancy, invert control: Have the class return the factory, and instrument the factory with a delegate that can create the class.
或者,如果你想变得更花哨,反转控制:让类返回工厂,并使用可以创建类的委托来检测工厂。
public class BusinessObject
{
public static BusinessObjectFactory GetFactory()
{
return new BusinessObjectFactory (p => new BusinessObject (p));
}
private BusinessObject(string property)
{
}
}
public class BusinessObjectFactory
{
private Func<string, BusinessObject> _ctorCaller;
public BusinessObjectFactory (Func<string, BusinessObject> ctorCaller)
{
_ctorCaller = ctorCaller;
}
public BusinessObject CreateBusinessObject(string myProperty)
{
if (...)
return _ctorCaller (myProperty);
else
return null;
}
}
:)
:)
回答by User
So, it looks like what I want cannot be done in a "pure" way. It's always some kind of "call back" to the logic class.
所以,看起来我想要的东西不能以“纯粹”的方式完成。它总是对逻辑类的某种“回调”。
Maybe I could do it in a simple way, just make a contructor method in the object class first call the logic class to check the input?
也许我可以用一个简单的方法来做,只需在对象类中创建一个构造方法,首先调用逻辑类来检查输入?
public MyBusinessObjectClass
{
public string MyProperty { get; private set; }
private MyBusinessObjectClass (string myProperty)
{
MyProperty = myProperty;
}
pubilc static MyBusinessObjectClass CreateInstance (string myProperty)
{
if (MyBusinessLogicClass.ValidateBusinessObject (myProperty)) return new MyBusinessObjectClass (myProperty);
return null;
}
}
public MyBusinessLogicClass
{
public static bool ValidateBusinessObject (string myProperty)
{
// Perform some check on myProperty
return CheckResult;
}
}
This way, the business object is not creatable directly and the public check method in business logic will do no harm either.
这样,业务对象就不能直接创建,业务逻辑中的公共检查方法也没有坏处。
回答by Jim Arnold
I don't understand why you want to separate the "business logic" from the "business object". This sounds like a distortion of object orientation, and you'll end up tying yourself in knots by taking that approach.
我不明白您为什么要将“业务逻辑”与“业务对象”分开。这听起来像是对物体方向的扭曲,采用这种方法最终会让自己陷入困境。
回答by Peter Morris
I'd put the factory in the same assembly as the domain class, and mark the domain class's constructor internal. This way any class in your domain may be able to create an instance, but you trust yourself not to, right? Anyone writing code outside of the domain layer will have to use your factory.
我会将工厂放在与域类相同的程序集中,并将域类的构造函数标记为内部。这样,您域中的任何类都可以创建实例,但您相信自己不会,对吗?任何在域层之外编写代码的人都必须使用您的工厂。
public class Person
{
internal Person()
{
}
}
public class PersonFactory
{
public Person Create()
{
return new Person();
}
}
However, I must question your approach :-)
但是,我必须质疑您的方法:-)
I think that if you want your Person class to be valid upon creation you must put the code in the constructor.
我认为,如果您希望 Person 类在创建时有效,则必须将代码放入构造函数中。
public class Person
{
public Person(string firstName, string lastName)
{
FirstName = firstName;
LastName = lastName;
Validate();
}
}
回答by Reuven Bass
In a case of good separation between interfaces and implementations the
protected-constructor-public-initializer pattern allows a very neat solution.
在接口和实现之间良好分离的情况下,
protected-constructor-public-initializer 模式提供了一个非常简洁的解决方案。
Given a business object:
给定一个业务对象:
public interface IBusinessObject { }
class BusinessObject : IBusinessObject
{
public static IBusinessObject New()
{
return new BusinessObject();
}
protected BusinessObject()
{ ... }
}
and a business factory:
和一个商业工厂:
public interface IBusinessFactory { }
class BusinessFactory : IBusinessFactory
{
public static IBusinessFactory New()
{
return new BusinessFactory();
}
protected BusinessFactory()
{ ... }
}
the following change to BusinessObject.New()
initializer gives the solution:
BusinessObject.New()
初始化程序的以下更改提供了解决方案:
class BusinessObject : IBusinessObject
{
public static IBusinessObject New(BusinessFactory factory)
{ ... }
...
}
Here a reference to concrete business factory is needed to call the BusinessObject.New()
initializer. But the only one who has the required reference is business factory itself.
这里需要引用具体的业务工厂来调用BusinessObject.New()
初始化程序。但唯一需要参考的是企业工厂本身。
We got what we wanted: the only one who can create BusinessObject
is BusinessFactory
.
我们得到了我们想要的:唯一可以创造的BusinessObject
是BusinessFactory
.