c# - 是否可以让通用子类在 c# 中看到相同变量的不同接口
问题描述
让我描述一个简化的故事。我尝试设计一个推荐功能,它会通过不同的匹配规则为你推荐不同的产品。
// TV will match a product by given TV related parameters
public class TvMatcher
{
public Product Match(ITvMatchParam tvMatchParam)
{
return new Product(); // pick a tv by tvMatchParam
}
}
public interface ITvMatchParam
{
int Age { get; }
int Gender { get; }
}
// Phone will match a product by given Phone related parameters
public class PhoneMatcher
{
Product Match(IPhoneMatchParam phoneMatchParam)
{
return new Product(); // pick a phone by phoneMatchParam
}
}
public interface IPhoneMatchParam
{
int Age { get; }
int Education { get; }
}
这Recommend
是一个接受联合参数的公共 API。然后它会选择一个 Matcher 并调用 match() 来选择一个产品。
public class Main
{
public Product Recommend(AllMatchParams allParams)
{
// pseudo code here, can't compile
IMatcher matcher = CreateMatcherFactoryMethod(allParams);
return matcher.Match(allParams);
}
private static IMatcher CreateMatcherFactoryMethod(AllMatchParams allParams)
{
IMatcher matcher;
if (allParams.Product == 0)
{
matcher = new TvMatcher();
}
else
{
matcher = new PhoneMatcher();
}
return matcher;
}
}
class AllMatchParams : ITvMatchParam, IPhoneMatchParam
{
public int Age { get; }
public int Education { get; }
public int Gender { get; }
public int Product { get; }
}
但是上面的代码不会被编译,因为 TvMatcher 和 PhoneMatcher 不能实现 IMatcher
public interface IMatcher
{
Product Match(AllMatchParams allMatchParams);
}
由于TvMatcher只关心Tv相关参数,PhoneMatcher只关心PhoneMatcher相关参数,我不想强制PhoneMatcher实现IMatcher。
public class PhoneMatcher: IMatcher
{
Product Match(AllMatchParams allParams)
{
// don't like this because PhoneMatcher only cares subset properties in allParams
}
}
所以我尝试实现一个 AbstractClass 并让 PhoneMatcher 继承它。我希望它可以接受 AllMatchParams 并且只在实现中看到 PhoneMatchParam。
public abstract class AbstractMatcher<TProductMatchParam>: IMatcher
{
public Product Match(AllMatchParams allMatchParams)
{
return ProductMatch(allMatchParams); // fails here
}
protected abstract Product ProductMatch(TProductMatchParam param);
}
public class PhoneMatcher: AbstractMatcher<IPhoneMatchParam>
{
protected Product ProductMatch(IPhoneMatchParam phoneMatchParam)
{
// ...
}
}
public class TvMatcher: AbstractMatcher<ITvMatchParam>
{
protected Product ProductMatch(ITvMatchParam tvMatchParam)
{
// ...
}
}
但是上面的代码不会编译,因为 AllMatchParams 不能转换为泛型变量<TProductMatchParam>
。
有没有办法让 AbstractMatcher.Match 可以接受一个固定类型的参数并委托给孩子,所以孩子可以看到该参数的不同接口?
我曾尝试向泛型变量添加约束,但失败了,因为无法同时IPhoneMatchParam
或ITvMatchParam
同时对 TProductMatchParam 进行约束。
解决方案
你AbstractMatcher
的有点过分了
您可以IMatcher
改为使您的界面通用:
public interface IMatcher<T>
{
Product Match(T matchParam);
}
public class PhoneMatcher: IMatcher<IPhoneMatchParam>
{
public Product Match(IPhoneMatchParam matchParam)
{
// ...
}
}
public class TvMatcher: IMatcher<ITvMatchParam>
{
public Product Match(ITvMatchParam matchParam)
{
// ...
}
}
在这种情况下,您可以通过AllMatchParams
2 种方法传递您的实例。
return new PhoneMatcher().Match(criteria) ?? new TvMatcher().Match(criteria);
将返回第一个非空匹配产品
推荐阅读
- r - R计算多个组中出现的重复项目
- c++ - 有没有办法在 C++ 的枚举中存储静态指针地址
- r - 如何使用 dplyr 检测面板数据中变量随时间的变化?
- firebase - 隐藏 Firebase 托管上的敏感数据
- nginx - Nginx ProxyPassReverse 设置
- python - 使用 py2neo 连接 Neo4j Aura 云数据库
- javascript - 在 div contenteditable 内自由移动图像
- java - 无法从 Spring Cloud Config Server 获取值到我的 Config-Client(limits-service)
- javascript - 如何在加载时检查 JavaScript 时间
- python - csv中的数据,双引号括起来的数据