我正在编写一个我认为很有可能使用基类的应用程序。我有Player
类,它为我的游戏中的每个玩家保存一个实例,我还有一个PlayerManager
类,其中包含所有连接玩家的字典,尽管我会将PlayerManager类保留在此之外问题,因为这只是关于Player和PlayerData类。
所以,我想在没有这样的东西之前请注意,在检查这段代码片段之前我已经删除了很多代码并且只显示了一个最小的例子。
class Player
{
public PlayerData;
}
class PlayerData
{
public string Username;
public string Motto;
public string NickName;
}
class SomeOtherClass
{
public void Test()
{
var player = GetPlayer();
Console.WriteLine("Hello, I am " + player.PlayerData.Username);
}
}
我想为什么有一个方法可以拥有一个基类?所以我认为很棒,让我们使用基类,这就是我最终的结果。
internal class Player : PlayerData, IDisposable
{
private readonly Socket _socket;
private bool _disposeCalled;
private bool _receivingData;
private bool _hasAuthenticated;
public Player(Socket socket)
{
_socket = socket;
}
public void OnAuthenticated(MySqlDataReader reader)
{
if (_hasAuthenticated)
{
return;
}
_hasAuthenticated = true;
AssignData(reader);
}
public void Dispose()
{
if (_disposeCalled)
{
return;
}
_disposeCalled = true;
if (_receivingData)
{
_receivingData = false;
try
{
if (_socket != null && _socket.Connected)
{
_socket.Shutdown(SocketShutdown.Both);
_socket.Close();
}
}
catch
{
// ignored
}
_socket?.Dispose();
}
if (_hasAuthenticated)
{
SaveData();
}
}
}
internal class PlayerData
{
public int Id;
public string Username;
public void AssignData(MySqlDataReader reader)
{
while (reader.Read())
{
Id = reader.GetInt32("id");
Username = reader.GetString("username");
}
}
public void SaveData()
{
using (var dbConnection = Program.Server.Database.Connection)
{
dbConnection.SetQuery("UPDATE `users` SET `username` = @username WHERE `id` = @id");
dbConnection.AppendParameter("id", Id);
dbConnection.AppendParameter("username", Username);
dbConnection.ExecuteNonQuery();
}
}
}
你可能会看到基类有一个构造函数,那是因为我只是用Player的构造函数传递PlayerData的数据,但我实际上并没有得到数据,直到玩家的类已经完全初始化,我不知道知道什么时候通过套接字数据包完成,我只是在我注意到它被认证时分配数据。
我的问题是,我应该使用这样的基类,还是我不应该使用基类,因为我没有通过构造函数初始化数据,或者可以通过后来的另一种方法?我真的需要一个基类,我是不是遵循正确的基本类和用于什么的官方规则?基本上我只是想知道,使用这个调用堆栈我应该使用基类还是方法?我不确定规则。
答案 0 :(得分:0)
因此,规则不是指导规则(并非每个人都真正同意)。
这就是说,我并没有真正看到将这些类集中在一起的任何好处,尽管这可能是因为删除了大量代码。
一般来说,一个好的经验法则是不使用继承,除非你有充分的理由 - 例如,通过组合无法实现大量的代码重用。在大多数情况下,如果您的设计着眼于减少依赖性(耦合),则代码将更容易维护,并且子类与其超类之间的依赖性非常强。这意味着保持分开。
您可以采取的一种简化对玩家数据调用的技巧是:#34;促进界面" - 基本上,在Player类上添加您想要的方法/属性作为一种外观,并且具有将代码中继到其PlayerData对象。这有一些好处: 1.它隐藏了对PlayerData的依赖,这意味着您可以自由地更改实现以合并或使用不同的类型(例如,如果您只想将这些值放在Player类的数据结构中) 2.它允许您处理请求PlayerData的情况,但尚未初始化。例如,您可以返回默认值或抛出自定义异常。 3. Player和PlayerData可以独立变化。因此,如果您遇到有效理由将其中一个或两个子类化,那么您就不会受到约束。
总之,看起来你通过这种方式使用继承并没有太大的收获,但它会在未来的时候切断设计选择。此外,任何时候您使用继承来描述不是" IS A"关系(PlayerData是玩家?不是) - 闻起来很腥。
再次,准则。最重要的是,您希望设计一个您想要维护的系统,并且设计决策需要权衡(通常在简单性和灵活性之间)。因此,如果您认为有充分的理由将其作为子类保留,请记录下来并且不要担心OO警察会因您违反规则而离开;)