遵循 DDD 实践,我在实现小型 AES 加密器/解密器(包装 .NET AesCryptoServiceProvider
)时遇到了问题。
public class Aes256CbcCryptor : ISymmetricCryptor
{
private SymmetricAlgorithm AesProvider { get; set; }
// Poor man's DI - beside the point
public Aes256Cbc()
{
this.AesProvider = new AesCryptoServiceProvider()
{
BlockSize = 128,
KeySize = 256,
Mode = CipherMode.CBC,
Padding = PaddingMode.PKCS7,
Key = // OH DEAR IT TAKES STATE
};
}
public Aes256Cbc(SymmetricAlgorithm aesProvider)
{
this.AesProvider = aesProvider;
}
public byte[] Encrypt(byte[] keyBytes, byte[] plaintextBytes)
{} // TODO
public byte[] Decrypt(byte[] keyBytes, byte[] ciphertextBytes)
{} // TODO
}
如您所见,.NETAesCryptoServiceProvider
是有状态的——它需要一个键作为属性。但据我了解,服务不应该是有状态的。
- 关键是属性(而不是方法参数)是这里的主要问题吗?
- 您将如何以 DDD 方式实现该类?
- 在某些情况下,使用给定密钥初始化提供程序似乎很有用且有效(如果要经常使用该密钥)。有状态服务是否有理由或替代方案?
我想我们可以在每个方法调用上实例化一个新的 Provider,但这似乎非常浪费。我们可以实施缓存来减少浪费,但整个事情开始感觉过度设计。
我想出的另一种选择是创建一个Aes256CbcCryptorFactory
代替。工厂CreateCryptor(byte[] key)
返回一个Aes256CbcCryptor
实际上是有状态的值对象。如果需要进行多次加密调用,消费服务现在至少可以将此对象保留在其方法之一的范围内。
另一方面,这样的消费服务仍然不能将值对象存储在它的一个属性中,因为这样做会使该服务成为有状态的。
- 看到有一些好处,这是做的事情吗?这种行为类型对于值对象来说似乎非常有用,但至少我们可以有一些临时状态。