人们总是定义一个私有成员,然后将构造函数参数值传递给它,比如设计A.但我无法理解这样做的好处,因为私有成员没有得到副本(我的意思是深度克隆)那么为什么不选择设计B呢?
设计A:
public class ClassA
{
public int num {get;set;}
}
public class ClassB
{
private ClassA a ;
public ClassB(ClassA _a) {
a = _a;
}
}
设计B:
public class ClassA
{
public int num {get;set;}
}
public class ClassB
{
public ClassA a {get; set;}
}
答案 0 :(得分:2)
设计A和设计B都很有用,但适用于不同的情况。
设计A的一个优点是,具有使用实例构造函数的参数初始化的私有实例字段,您知道字段a
的“标识”不会被任何人(外部任何人)更改只要ClassB
对象存在,类本身)。所以你可以根据这个做出假设。这为Design A提供了一种设计B缺乏的浅层不变性。
您还可以使用自动属性(而不是显式字段)创建设计A.只需创建自动属性set;
的{{1}}访问者。
答案 1 :(得分:1)
这些设计都很好,视情况而定。 两者都是一种依赖注入,有4种类型的依赖注入:
我不会详细说明你在这里没有使用的2种类型,但是它们与Mark Seeman的.NET中的依赖注入
中的其他2个一起讨论设计A是构造函数依赖注入,其优点是它是最简单的依赖注入类型。您首选的依赖注入是这一个。如果注入的依赖项没有良好的默认值,这是完全正常的。构造对象后,依赖关系不会更改。 默认使用这种依赖注入可能会导致构造函数中包含许多参数的类。这被称为依赖注射。 我遵循Mark Seeman在他的书中所做的相同代码,所以我有这样的代码:
public class TekeningViewModel : ViewModelBase
{
private readonly IUnitOfWorkAsync _unitOfWork;
TekeningViewModel(IUnitOfWorkAsync _unitOfWork){
if (unitOfWork == null)
{
throw new ArgumentNullException("unitOfWork");
}
_unitOfWork = unitOfWork;
}
}
注意readonly
类型的成员,并检查传递的参数是否为空。
设计B是理想的。因为那时可能没有调用属性setter,并且自动在构造函数中设置了一个好的默认值。设计B也是strategy pattern
。在设计A的地方,并不打算在飞行中改变为不同的依赖,在构造之后,即设计B,你可以做到这一点。在多线程环境中,这增加了以安全方式实现它的方式的复杂性。如上所述,设计B导致的代码多于设计A.
选择合适的默认值时必须小心,因为您不希望仅因默认值而创建对程序集的依赖关系。任何使用您的类的人,即使那些不使用该默认值的人,仍然会依赖包含该默认值的程序集。
进行依赖注入的第三种方式是这样的:
Aclass{
void methodinjection(int a, Bclass b){
///
}
}
并且执行依赖注入的第四种方式是这样的:
Aclass{
void methodinjection(int a){
AmbientContext::getInstance().getBclass();
//....
}
}
设计的复杂性从1增加到4。 类型4看起来像一个单例,它是一个反模式,所以它是我最不喜欢的依赖注入类型,但它确实有其优点。因为Ambient上下文本身应该使用前两种类型的依赖注入来创建,因此具有很大的灵活性。非常适合将交叉切割问题传递给应用程序,而不会使用太多参数污染构造函数。
答案 2 :(得分:0)
我对C ++的熟悉程度高于C#,但如果我理解正确,那就是用成员函数调用它。你的问题在这里得到了很好的回答:What is the use of making constructor private in a class?
答案所指的工厂模式是Factory Pattern的一部分;请参阅用例链接。
答案 3 :(得分:0)
我看到设计A只有一个带有一个参数的构造函数,并且没有默认的构造函数。所以这个设计强制规则只能通过在创建Class B对象时传递Class A的对象来创建对象类B,如果你不知道Class A的值,你就不能为B类创建对象,至少你有显式传递null。
在设计B中,没有这样的规则实施,因为有一个默认构造函数,你可以在创建B类后推迟A类对象的赋值。