【发布时间】:2015-09-17 18:33:11
【问题描述】:
我正在开发一些软件,其中字符串消息中使用的某些字符串标识符指的是生产地址或测试地址。有一种公式化的方法可以将生产标识符转换为测试标识符。
但是,只有一套硬件——不是用于生产和测试的独立系统。
每次我们连接到一个新的收件人时,都会有一个针对该收件人的初始开发和测试阶段,我们希望标识符能够安全地转换为测试标识符,这样就不会意外发送实际的生产消息。现在,消息生成类似乎不适合了解 test 与 prod——这应该是“愚蠢的”,因为 test 与 prod 是业务级别的问题。但是,消息生成项目包含Identifier 类,因为它负责接受此类标识符并对其进行序列化。
如何在消息生成项目中保留Identifier 的定义,但确保在适当时将其中实际使用的所有标识符转换为其等效的测试,而不会在业务中到处乱扔程序/条件语句层?
在消息生成项目中,这里有一些Identifier 的示例代码。
public sealed class Identifier {
private readonly string _identifier;
public Identifier(string identifier) {
_identifier = identifier;
}
public IdentifierCode { get { return _identifier; } }
public bool IsTest { get { return _identifier.BeginsWith("X"); } }
public Identifier ToTestIdentifier() {
return new Identifier("X" + _identifier.Substring(1);
}
}
在业务层,这里有一个如何构造和使用标识符的示例。
...
Message1234 message = new MessageBuilder { // from the generation layer
Sender = new Identifier(messageDetails.senderIdentifierCode),
Recipient = new Identifier(messageDetails.recipientIdentifierCode),
MessageDate = DateTime.Parse(messageDetails.date)
}.Build<Message1234>;
我可以使用什么样的设计模式,以确保根据某些对接收者敏感的过程逻辑(访问未在代码中提交或至少仅在 ONE 中提交的数据库或设置文件地方),当特定收件人处于测试模式时,上面创建的Identifier 属性将始终运行ToTestIdentifier?
例如,如果recipientIdentifierCode 是AARDVARK(因为已知该收件人处于测试状态),则消息生成中使用的所有标识符都将成为测试标识符,但如果recipientIdentifierCode 是GORILLA(如该接收者已知处于生产状态),所有标识符都保持原样,无论它们是生产还是测试?
为了更清楚,我试图避免这种情况:
Identifier sender = new Identifier(messageDetails.senderIdentifierCode);
Identifier recipient = new Identifier(messageDetails.recipientIdentifierCode);
Message1234 message = new MessageBuilder {
Sender = IsInTestMode(messageDetails.recipientIdentifierCode)
? sender.ToTestIdentifier()
: sender,
Recipient = IsInTestMode(messageDetails.recipientIdentifierCode)
? recipient.ToTestIdentifier()
: recipient,
MessageDate = DateTime.Parse(messageDetails.date)
}.Build<Message1234>;
这很脆弱,因为它依赖于开发人员记住,每个地方都使用Identifier,以便根据适当的规则(可能会改变的规则)进行上下文测试。它还将代码混杂到用于构建消息的算法中,以及与业务实体的测试/产品状态无关的关注点。我想在调用链中的某处进行依赖注入、装饰或提供访问者,或 一些东西,让我能够做到这一点,只需 一次 每个消息请求:
// Hit the database or do some procedural logic to figure out if test mode is required.
bool shouldBeTestMode = GetTestModeFor(messageDetails.recipientIdentifierCode);
// activate some layer or create some object that wraps/translates/informs
// the rest of the system
MessageGenerationContext = new MessageGenerationContext(shouldBeTestMode);
GoBuildMessages(MessageGenerationContext);
// Now the magic happens somehow so that `new Identifier()` will always return a
// test identifier without any more code going through conditional contortions
// to make sure the proper kind of identifiers are used.
哦,为了配合我的问题标题,我想让业务层中的随机代码很难或不可能在不执行确定是否需要进行测试的特殊逻辑的情况下创建Identifier一个与否,并转换它。只有消息层消费者中的特定特权位置才能访问Identifier 构造函数。所有其他 new Identifier() 代码(或其他创建标识符的方法)都应该被适当地缓冲,因此它不能构建任何测试上下文不敏感的标识符。
【问题讨论】:
-
为什么不使用带有设置的 app.config 配置文件进行生产或测试?然后在
Identifier类中,您可以检查此标志,如果设置了它,则返回测试标识符而不是生产标识符。 -
Identifier类是消息生成项目的一部分,它不应该知道这个设置,或者至少不应该知道如何在数据库中查找哪些收件人需要测试或生产.您是否建议我创建一个带有 test/prod bool 参数的 IdentifierGenerator 类,然后在当前代码执行new Identifier()之后我改为执行IdentifierGenerator.Generate()?一种全局设置是不够的。 -
这是一种方法,但是检查
Identifier类中的配置标志有什么问题?这里没有数据库操作,app.config 文件始终可以通过System.Configuration.ConfigurationManager访问,您可以只测试“测试”设置是否存在,假设生产如果不存在,则在构造函数中创建一个真正的标识符或以“X_”为前缀进行测试。 -
@Ron 我可能欠你一个道歉。我现在在我的问题中澄清了我的需求——我不应该提出一个全局测试/产品标志场景。它确实需要对收件人敏感。
-
当您使用带有属性初始化的 MessageBuilder 时,为什么不向它添加一个处理该逻辑的构造函数。要求您的开发人员使用具有 messageDetails 对象作为参数的构造函数。你已经涵盖了你的 DRY 原则。此外,您可以提供一个 DI 注入类,为接收者提供有关测试模式的知识。
标签: c# design-patterns separation-of-concerns