【发布时间】:2011-03-02 06:43:51
【问题描述】:
我希望标题听起来不要太主观;我绝对不是要开始对 OO 进行一般性辩论。我只想讨论解决以下问题的不同方法的基本优缺点。
让我们举这个最小的例子:你想表达一个抽象数据类型 T 的函数可能会将 T 作为输入、输出或两者兼有:
- f1 :接受一个 T,返回一个 int
- f2 :接受一个字符串,返回一个T
- f3 :接受一个 T 和一个 double,返回另一个 T
我想避免向下转换和任何其他动态类型。我还想尽可能避免突变。
1:基于抽象类的尝试
abstract class T {
abstract int f1();
// We can't have abstract constructors, so the best we can do, as I see it, is:
abstract void f2(string s);
// The convention would be that you'd replace calls to the original f2 by invocation of the nullary constructor of the implementing type, followed by invocation of f2. f2 would need to have side-effects to be of any use.
// f3 is a problem too:
abstract T f3(double d);
// This doesn't express that the return value is of the *same* type as the object whose method is invoked; it just expresses that the return value is *some* T.
}
2:参数多态性和辅助类
(TImpl 的所有实现类都将是单例类):
abstract class TImpl<T> {
abstract int f1(T t);
abstract T f2(string s);
abstract T f3(T t, double d);
}
我们不再表示某些具体类型实际上实现了我们最初的规范——实现只是一个类型 Foo,我们恰好有一个 TImpl 的实例。这似乎不是问题:如果您想要一个适用于任意实现的函数,您只需执行以下操作:
// Say we want to return a Bar given an arbitrary implementation of our abstract type
Bar bar<T>(TImpl<T> ti, T t);
此时,不妨完全跳过继承和单例并使用
3 一级功能表
class /* or struct, even */ TDict<T> {
readonly Func<T,int> f1;
readonly Func<string,T> f2;
readonly Func<T,double,T> f3;
TDict( ... ) {
this.f1 = f1;
this.f2 = f2;
this.f3 = f3;
}
}
Bar bar<T>(TDict<T> td; T t);
虽然我看不出 #2 和 #3 之间的实际区别。
示例实现
class MyT {
/* raw data structure goes here; this class needn't have any methods */
}
// It doesn't matter where we put the following; could be a static method of MyT, or some static class collecting dictionaries
static readonly TDict<MyT> MyTDict
= new TDict<MyT>(
(t) => /* body of f1 goes here */ ,
// f2
(s) => /* body of f2 goes here */,
// f3
(t,d) => /* body of f3 goes here */
);
想法? #3 是单调的,但看起来相当安全和干净。一个问题是它是否存在任何性能问题。我通常不需要动态调度,如果这些函数体在静态已知具体实现类型的地方静态内联,我更喜欢。 #2 在这方面更好吗?
【问题讨论】:
-
这段代码的下一个维护者将是一个知道你住在哪里的杀人狂。他讨厌沙拉,只吃牛排。当然很少见。
-
如果您反对,我实际上不会调用函数 f1、f2 和 f3 ;)
-
这是一个学术练习,还是有实际案例证明这种实施是有益的?
-
您在这里所做的是创建一个完全由函数而不是对象定义的完全人为的示例,并询问我们方法表是否适合它的设计。嗯,是的,确实是这样,但这就像向我们展示一个马蜂窝的流量控制路径并询问
goto是否是一个很好的解决方案。您为什么不给我们一些领域要求的想法,以便我们评估其中任何一项对于它旨在解决的实际问题是否必要或有用? -
@Aaronaught:他试图模拟一种比接口和继承支持的更具表现力、更通用的多态风格。考虑一个类
Collection表示一个单一类型的对象的排序列表;定义一个类型安全的接口Sortable,这样可以比较同一类的两个对象,但比较不同的类是类型错误。 .NET 框架通过 List.Sort() 采用比较 参数来实现这一点——换句话说,由函数定义。当一个功能不足时,此问题中的代码寻求更通用的解决方案。
标签: c# generics oop functional-programming polymorphism