我正在阅读Josh Bloch的书 Effective Java ,他建议在构建具有大量成员的对象时使用构建器设计模式。从我所看到的不是香草设计模式,而是看起来像他的变化。我更喜欢它的外观,并试图在我正在编写的C#Web应用程序中使用它。这是用Java编写的代码并且运行良好
public class Property {
private String title;
private String area;
private int sleeps = 0;
public static void main(String[] args) {
Property newProperty = new Property.Builder("Test Property").Area("Test Area").Sleeps(7).build();
}
private Property(Builder builder) {
this.title = builder.title;
this.area = builder.area;
this.sleeps =builder.sleeps;
}
public static class Builder{
private String title;
private String area;
private int sleeps = 0;
public Builder (String title){
this.title = title;
}
public Builder Area(String area){
this.area = area;
return this;
}
public Builder Sleeps(int sleeps){
this.sleeps = sleeps;
return this;
}
public Property build() {
return new Property(this);
}
}
}
当我把它放到我认为的C#等价物
时 public class Property
{
private String title;
private String area;
private Property(Builder Builder)
{
title = Builder.title;
area = Builder.area;
}
public static class Builder
{
// Required parameters
private String title;
private String area;
// Optional parameters
private int sleeps = 0;
public Builder(String val)
{
this.title = val;
}
public Builder Area(String val)
{
this.area = val;
return this;
}
public Builder Sleeps(int val)
{
this.sleeps = val;
return this;
}
public Property build()
{
return new Property(this);
}
}
}
然后我收到编译器警告。他们中的大多数“无法在静态类中声明实例成员”。
所以我的问题首先是我错过了什么?如果我错过了某些东西,我可以按照Josh Bloch推荐的方式进行,但是在C#中,最后,这个也很重要,这个线程安全吗?
答案 0 :(得分:13)
public static class
意味着您定义了一个静态嵌套类。这意味着它在逻辑上包含在另一个类中,但它的实例可以存在而不需要引用它的外部类。非静态嵌套类称为“内部类”,它的实例只能存在于外部类的实例中。
在C#中,static class
是一个无法实例化的,因此不能拥有任何非静态成员。在Java中没有与此构造等效的直接语言级别,但您可以通过仅提供私有构造函数来轻松阻止Java类的实例化。
简短的Java回顾:
static
的嵌套类称为内部类static
嵌套类没有单独的名称static
嵌套类在很大程度上独立于其外部类(某些特权访问除外)。如果有些C#guru告诉我们如何在C#/ .NET中处理内部/嵌套类,我会很高兴。
答案 1 :(得分:3)
我认为如果您将Builder创建为顶级类(因为它与Java完全相同),您可以实现几乎相同的效果,并创建一个工厂方法来接收构建器以保持构造函数的私有性(反过来会让你返回子类实例(如果需要)。
重点是让构建器执行创建对象所需的步骤。
所以(不太了解C#你可以尝试这样的事情)
// My naive C# attempt:P
public class Property
{
public static void main( String []args )
{
Property p = Property.buildFrom( new Builder("title").Area("area").Etc() )
}
public static Property buildFrom( Builder builder )
{
return new Propert( builder );
}
private Property ( Builder builder )
{
this.area = builder.area;
this.title = builder.title;
// etc.
}
}
public class Builder
{
public Builder ( String t )
{
this.title = t;
}
public Builder Area( String area )
{
this.area = area;
return this;
}
// etc.
}
将Builder作为静态内部属性类的重点是在两者之间创建一个高耦合(就好像它们在哪一个)。这就是为什么Builder中的构建方法调用私有的“Property”构造函数。
可能在C#中,您可以使用替代工件来创建相同的耦合。
答案 2 :(得分:2)
在Java中,嵌套类默认与其包含类的特定实例相关联。嵌套类的实例可以访问包含实例的变量和方法。如果嵌套类具有“static”关键字,则它不与外部类的实例关联。从这个意义上说,Bloch在Builder类中使用“static”关键字。
“静态”意味着在C#中应用于嵌套类时会有所不同。我不知道你在C#中使用什么关键字,或者即使它是必要的。您是否尝试将静态关键字从类定义中删除?
在Java类定义中使用“static”在Effective Java的第18项中讨论。
答案 3 :(得分:2)
saua有正确的答案,但我想特别清楚你的例子:
在C#版本中,您应该从内部类中删除static关键字。它与Java版本的含义不同,实际上它在Java版本中的作用是C#中内部类的 normal 行为。
答案 4 :(得分:1)
我不确定Java在静态类声明中做了什么,但在C#中,静态类只有类级成员,并且根据定义,不能实现到实例中。这就像Class和Module之间的旧VB差异。
答案 5 :(得分:0)
我不知道为什么C#会抱怨,但我可以说代码是线程安全的。如果您同时创建两个或更多Property
个实例,每个实例都在自己的主题中,则不会遇到任何问题。
答案 6 :(得分:0)
我会尝试删除static关键字。正如其他人已经建议的那样,我的另一个想法是将构建器类创建为顶级类。
答案 7 :(得分:0)
要回答几条关于如何在C#中获取Java内部类行为的评论,似乎需要在内部类的构造函数中传递对封闭类的引用(从快速的Google - C#可能已添加)能力)。
public class Outer
{
...
void SomeMethod() {
Inner workerBee=new Inner(this);
}
...
class Inner
private Outer outer;
{
Inner(Outer out) {
outer=out;
}
}
}
因此,C#只是明确了Java的含义,包括显式需要引用来访问外部类的成员。
就个人而言,我从来没有喜欢Java外部类成员的隐式访问,因为它似乎太容易绊倒并意外地破坏封装 - 我几乎总是将我的内部类创建为静态并将它们传递给外部类的引用
答案 8 :(得分:0)
假设您的类具有与构建器成员对应的公共可设置属性,则不需要在C#中使用Bloch的构建器模式。您可以使用对象初始值设定项:
public class Property
{
public String Title {get; set};
public String Area {get; set};
public int Sleeps {get; set};
public static void main(String[] args)
{
Property newProperty = new Property {Title="Test Property", Area="Test Area", Sleeps=7};
}
}
如果您需要更多封装,这将无法实现。