我正在开发一个使用两个主要抽象级别的应用程序:
应用程序本身从SDK库中实例化类,并使用它们来满足核心库的依赖关系。
我需要解决的问题通常是这样的:
// Algorithm in the core (interfaces are all implemented by the SDK library):
ICorrespondentRepository allCorrespondents = ...;
ICorrespondent correspondent = allCorrespondents.FindByName(...);
...
IDocumentRepository allDocuments = ...;
IDocument document = allDocuments.FindByTitle(...);
// Problem: Implementation needs state not exposed
// on ICorrespondent in order to do this:
document.SetRecipient(correspondent);
换句话说:IDocument
可以将其收件人设置为之前获得的ICorrespondent
。调用SetRecipient
时,IDocument
的实现需要状态(对核心不重要的主键)与 - ICorrespondent
不相关,以便实际影响更改。
实现这一目标的一种方法是将ICorrespondent
向下转换为SetRecipient
内的实际实现类,但这感觉非常笨重。更糟糕的是保持从接口引用到内部状态的映射。
问题的根源似乎是接口专门用于满足核心库的通用需求,即使它们实际上有两个具有不同要求的消费者:核心和生成它们的实现库。 / p>
有没有更好的方法来重新设计这种要求?
答案 0 :(得分:1)
实际上,你想要做的就是交叉投射。
您说IDocument
的具体实施与ICorrespondent
的所有子类不兼容,因此如果SetRecipient
的实例,您对ICorrespondent
的调用可能会合法地失败传递没有这个主键。拥有此主键是兼容子类的“特征”。
您可以使用的技术就是这个。定义一个界面。
internal interface IHasPrimaryKey {
PrimaryKey GetPrimaryKey();
}
兼容的ICorrespondent
类应该实现两个接口。
internal class CompatibleCorrespondent : ICorrespondent, IHasPrimaryKey {
// ...
}
在这种情况下,SetRecipient
应该尝试对方的交叉演员,看看它是否提供了必要的主键,否则就失败了。
var hasPrimaryKey = correspondent as IHasPrimaryKey;
if(hasPrimaryKey == null) {
throw new InappropriateSubclassException();
}
// ...
var pk = hasPrimaryKey.GetPrimaryKey();
这是您可以从这种架构中获得的最强类型的解决方案。失败案例是合法的,因为类型系统并不能保证您在每种情况下都能获得主键。
这样做的好处是你没有绑定到特定的子类。任何同时实现ICorrespondent
和IHasPrimaryKey
的类都是合适的。
当然,我会让您为特定代码找到更合适的名称。