假设我有一个简单的TCP服务,在接受连接时,会分叉一个新线程并调用 initializeClient clientSocket 。
initializeClient看起来像这样:
initializeClient clientSocket = do
clientDataTVar <- atomically $ newTVar (UnregisteredClientData clientSocket)
_ <- forkIO $ clientSocketReadLoop clientDataTVar
为简单起见,我们假设clientDataTVar中只有两个可能的实例:
data UnregisteredClientData = UnregisteredClientData {
ucdSocket :: Socket
}
data CustomerClientData = CustomerClientData {
ccdSocket :: Socket,
ccdName :: Text
}
当未注册的客户端发送包含其名称的消息时,其ClientDataTVar值将被替换:
writeTVar unregisteredClientDataTVar $ CustomerClientData clientSocket theirName
编辑:上面的writeTVar行不会进行类型检查,因为TVar的类型是 TVar UnregisteredClientData 。 CustomerClientData无法写入其中,但我将其留在此处以说明我想要实现的目标。
此时,命令的处理程序返回,clientSocketReadLoop再次运行。
clientSocketReadLoop只对Socket感兴趣,所以我可以做以下事情:
class ClientData a where
cdSocket :: a -> Socket
instance ClientData UnregisteredClientData where
cdSocket = ucdSocket
instance ClientData CustomerClientData where
cdSocket = ccdSocket
现在,当clientSocketReadLoop读取clientDataTVar,它可以调用的 cdSocket clientData 并检索插座,不管基本类型是UnregisteredClientData或CustomerClientData的。在执行recv之后,它需要调用一个处理程序。究竟要调用哪个处理程序取决于用户类型(未注册或客户)。
我相信这可以通过将handleMessage添加到类和实例来实现:
class ClientData a where
cdSocket :: a -> Socket
handleMessage :: a -> String -> IO ()
instance ClientData UnregisteredClientData where
cdSocket = ucdSocket
handleMessage unregisteredClientDataTVar msg = (implementation)
instance ClientData CustomerClientData where
cdSocket = ccdSocket
handleMessage customerClientDataTVar msg = (implementation)
因此,调用适当的处理程序。
我想知道的是:
这是一个很好的方法吗?我想这是一个相当标准的场景,虽然我使用TVar用于ClientData,而其他人可能只是通过Socket。这不应该有太大变化。
如果这是一个好方法,是否可以将类/实例定义放在一个文件(Types.hs)中并在另一个文件(Client.hs)中实现处理程序?
提前致谢!
答案 0 :(得分:0)
我认为我不会在这里使用类型类。当你想要处理一小组有限的案例时,使用代数数据类型要简单得多。
例如,
data ClientData = ClientData { cdSocket :: Socket, cdName :: Maybe Text }
或者如果您想要比Maybe
更明确的内容,
type Name = Text
data UserInfo = Unregistered | Customer Name
data ClientData = ClientData { cdSocket :: Socket, cdUserInfo :: UserInfo }
然后,您可以使用模式匹配来处理不同的情况:
handleMessage clientData msg =
case cdUserInfo clientData of
Unregistered -> -- implementation
Customer name -> -- implementation