我一直在处理一些抽象的课程,感觉不舒服,但我不知道该怎么做。这是一个简单的例子来解释我的问题:
public abstract class Data
{
protected Boolean _Connected = false;
public abstract void Connect();
public abstract void Disconnect();
public Boolean Connected
{
get { return _Connected; }
}
}
public class SqlServerData : Data
{
public override void Connect()
{
// code to connect to sql server
_Connected = true;
}
public override void Disconnect()
{
if (_Connected)
{
// code to disconnect from sql server
_Connected = false;
}
}
}
我的设计存在一些问题。
此设计中的任何内容都不会强制Data的新实现对_connected实例变量执行任何操作。如果使用Data类的其他类依赖于Connected属性,则可能不准确。
对于此代码的新用户,可能会感到困惑。此示例非常简单,但如果抽象类中有更多实例变量,而SqlServerData类中有其他实例变量,则更难以了解变量的定义位置。
所以我的问题是,这是否应该重构,如果是,如何?
答案 0 :(得分:6)
在基类中实现状态机(已连接或未连接,以及这些状态之间的转换),因此派生类不必担心此部分。为实际功能提供受保护的方法,因此派生类可以轻松填写“漏洞”:
public abstract class Data
{
private bool connected;
public bool Connected
{
get { return connected; }
}
public void Connect()
{
OnConnect();
connected = true;
}
public void Disconnect()
{
if (connected)
{
OnDisconnect();
connected = false;
}
}
protected virtual void OnConnect() { }
protected virtual void OnDisconnect() { }
}
和
public class SqlServerData : Data
{
protected override void OnConnect()
{
// code to connect to sql server
}
protected override void OnDisconnect()
{
// code to disconnect from sql server
}
}
答案 1 :(得分:3)
问题在于您希望逻辑管理 _connected 标志以在所有子类之间共享,但仍保留每个子类提供其实际调用时所发生情况的实现的能力连接()和断开连接()。为此,我建议使用所谓的Template Method Pattern,这样抽象基类仍然可以保留对方法中使用的逻辑的一些控制。它的工作方式非常简单,只需构建类似于此的类:
public void Connect() {
if(!_connected) {
ExecuteConnect();
_connected = true;
}
}
public void Disconnect() {
if(_connected) {
ExecuteDisconnect();
_connected = false;
}
}
protected abstract void ExecuteConnect();
protected abstract void ExecuteDisconnect();
现在在你的基类中你可以覆盖Execute *方法(我确定可以改进命名约定),这样你就可以为连接和断开连接提供新的实现,同时仍然可以管理对通用算法的控制。
答案 2 :(得分:0)
我宁愿将属性Connected
抽象化并省略受保护的字段。
受保护领域的缺点是基地和儿童必须以一致的方式使用它,从而将它们结合在一起。
但是拥有受保护的字段可能会为您节省一些简单的代码。这取决于实际问题,但通常我宁愿写几行代码然后引入耦合。