多阶段状态的嵌套 类
Nested classes for a multiple-phase state
我想使用嵌套 classes 作为 "developing state":
public class WebSvcClient : IDisposable
{
//
// 10 private fields required by all methods
...
public Profile Profile { get; private set; }
public void Authenticate()
{
this.Profile = new Profile();
}
public class Profile
{
// public methods that do require authentication
...
}
// public methods that don't require authentication
...
}
我可以看到几个好处:
- 封装,
Profile
只有在WebSvcClient
的上下文中才有意义
- 单
IDisposable
单元
- 不需要第 3 个 class 只是将私有字段传递给
Profile
- 命名空间无污染
但这被认为是好的做法吗?
没有好处:
- 封装是关于修饰符的。您的嵌套 class 及其方法是 public。如果你不从外部到达嵌套class,你可以使用私有class进行污染。
- IDisposable 单元仅与实施者 class 相关。嵌套的 class 不会受到影响。
- 污染不是来自名称空间,而是来自糟糕的设计和糟糕的命名习惯。请记住,您不是唯一的开发人员。下一个开发人员必须了解您的代码,因此他们应该通过浏览文件名轻松查看代码。或者他们必须逐个文件检查所有代码。
我认为这里没有任何收获。
- Encapsulation, Profile makes sense only in the context of WebSvcClient
但是在另一个 class 中使用私有字段,即使它是嵌套的,也会破坏封装。
- Single IDisposable unit
它引起的问题比在这里解决的问题多。如果在处理服务后其他代码保留配置文件怎么办?
- Lack of need for 3rd class just to pass the private fields to Profile
好吧,也许吧。 class 无论如何都会很乱。
- No pollution of namespace
无论如何,这不是真正的问题。
作为替代方案,使用两个接口,或至少一个用于配置文件部分。显式实现相关成员,以便它们只能通过 IProfile
引用使用。
这可以通过铸造来规避,但如果这是一个问题,您应该与您的团队交谈。这对图书馆很重要,但对应用程序不重要。
考虑使用表示状态的接口,以及可以从一种状态转换到另一种状态的方法:
public interface INew {
// transition to initialized state
IInitialized Init();
}
和
public interface IInitialized {
// connect to get a connected object
IConnected Connect(string connection);
}
和
public interface IConnected {
// disconnect reverts back in state
IInitialized Disconnect();
// methods only available when connected
bool GetValue(string name);
void SetValue(string name, bool value);
}
等等
您可以在公共 class 上实现这些接口,或者为每个状态使用不同的 class。您将需要某种工厂来创建初始实例。
当您完全控制实际状态(没有意外断开等)时,这很有效。
通过这种方式,您可以告诉 API 的用户他们需要做什么,按什么顺序才能访问所需的方法。您可以使用 'fluent' 代码来使用这个:
var newMachine = Factory.NewMachine();
var connected = newMachine
.Init()
.Connect(connectionString);
connected.GetValue("test");
...
connected.Disconnect();
我想使用嵌套 classes 作为 "developing state":
public class WebSvcClient : IDisposable
{
//
// 10 private fields required by all methods
...
public Profile Profile { get; private set; }
public void Authenticate()
{
this.Profile = new Profile();
}
public class Profile
{
// public methods that do require authentication
...
}
// public methods that don't require authentication
...
}
我可以看到几个好处:
- 封装,
Profile
只有在WebSvcClient
的上下文中才有意义
- 单
IDisposable
单元 - 不需要第 3 个 class 只是将私有字段传递给
Profile
- 命名空间无污染
但这被认为是好的做法吗?
没有好处:
- 封装是关于修饰符的。您的嵌套 class 及其方法是 public。如果你不从外部到达嵌套class,你可以使用私有class进行污染。
- IDisposable 单元仅与实施者 class 相关。嵌套的 class 不会受到影响。
- 污染不是来自名称空间,而是来自糟糕的设计和糟糕的命名习惯。请记住,您不是唯一的开发人员。下一个开发人员必须了解您的代码,因此他们应该通过浏览文件名轻松查看代码。或者他们必须逐个文件检查所有代码。
我认为这里没有任何收获。
- Encapsulation, Profile makes sense only in the context of WebSvcClient
但是在另一个 class 中使用私有字段,即使它是嵌套的,也会破坏封装。
- Single IDisposable unit
它引起的问题比在这里解决的问题多。如果在处理服务后其他代码保留配置文件怎么办?
- Lack of need for 3rd class just to pass the private fields to Profile
好吧,也许吧。 class 无论如何都会很乱。
- No pollution of namespace
无论如何,这不是真正的问题。
作为替代方案,使用两个接口,或至少一个用于配置文件部分。显式实现相关成员,以便它们只能通过 IProfile
引用使用。
这可以通过铸造来规避,但如果这是一个问题,您应该与您的团队交谈。这对图书馆很重要,但对应用程序不重要。
考虑使用表示状态的接口,以及可以从一种状态转换到另一种状态的方法:
public interface INew {
// transition to initialized state
IInitialized Init();
}
和
public interface IInitialized {
// connect to get a connected object
IConnected Connect(string connection);
}
和
public interface IConnected {
// disconnect reverts back in state
IInitialized Disconnect();
// methods only available when connected
bool GetValue(string name);
void SetValue(string name, bool value);
}
等等
您可以在公共 class 上实现这些接口,或者为每个状态使用不同的 class。您将需要某种工厂来创建初始实例。
当您完全控制实际状态(没有意外断开等)时,这很有效。
通过这种方式,您可以告诉 API 的用户他们需要做什么,按什么顺序才能访问所需的方法。您可以使用 'fluent' 代码来使用这个:
var newMachine = Factory.NewMachine();
var connected = newMachine
.Init()
.Connect(connectionString);
connected.GetValue("test");
...
connected.Disconnect();