【问题标题】:Type safety with object-oriented methods面向对象方法的类型安全
【发布时间】:2012-05-24 14:15:01
【问题描述】:

我正在考虑如何使用面向对象的方法正确解决这个问题。语言并不重要——我其实很想写代码,但我更关心的是一般原则。

我想实现一个field:一个“数字”的集合,+、-、* 和 / 操作在这些“数字”上进行。此外,我希望能够实现更高的操作,例如 ^ 和循环查找,其中 (1) 不需要为给定字段定义,但 (2) 可以在需要时被覆盖,例如出于效率原因。

问题来了。声明还不够好

FieldElement power (FieldElement base, FieldElement exponent)

因为我想要类型安全:不可能将有限域的成员添加到整数。

也许我真正在寻找的是元对象,或超级接口,或将不同类联系在一起的东西(一个用于整数,一个用于 7-adics,一个用于有限域 F_4 等) .或者也许有更好的东西。

注意欢迎(甚至鼓励)在答案中使用代码,如果它有启发性的话,但声明可能就足够了:大概这里的每个人都可以为至少几个领域写出明显的方法。


我会提到其他对我很重要但(显然)与主要 OO 问题无关的条件:我不希望字段元素携带它们的类型信息,而且我希望它们是轻量级的(因为我可能需要处理大量的字段元素)。这些需求可能无法实现——尽管坦率地说,我更可能在这里放弃面向对象而不是效率。但无论如何,我们都将不胜感激,因为我有兴趣了解这些问题,即使除了手头的特定问题。

【问题讨论】:

  • “语言不重要”——我很确定。例如,对此的 C++ 解决方案可能是模板,它在 Java 中不存在(它们确实存在,某种程度上,以泛型的形式)。
  • 嗯,这不太正确。例如,您可以说这需要有界参数多态性,并且鉴于此,您在语言 X 中能做的最好的事情就是使用特征 Y。语言特征并不是孤立存在的——人们在计算机上工作是有报酬的 科学 ...但我想你可能会争辩说你最好在不同的网站上问这个问题(compsci 是什么?)
  • 你可以试试cs.stackexchange.com
  • 这是一个我觉得可以在几个不同的地方问的问题的例子。我确定它会在 cstheory.se 关闭,但也许 cs.se 会接受它。
  • 嗯。我不知道两者都存在。 cstheory是研究吗?无论如何,就个人而言,我很高兴你在这里问。对空指针、采访和正则表达式进行更改。

标签: oop language-agnostic computer-science liskov-substitution-principle


【解决方案1】:

这称为二元方法问题。快速谷歌搜索将显示一些(大量)信息。尤其是Luca Cardelli等人的《论二元方法》一文,对这个问题进行了彻底的处理。

您可能想学习一些 Haskell 来了解实用的编程语言如何处理这个问题。

编辑洛卢卡 → 卢卡。该死的小手机屏幕和更小的键盘;)

【讨论】:

    【解决方案2】:

    我之前尝试过用C#来表达这些概念,但是遇到了语言障碍:语言不够丰富,或者不够具体。例如,如果我这样定义一个字段的元素:

    public abstract class FieldElement 
    {
        public abstract FieldElement Add(FieldElement another);
        public abstract FieldElement SumInvert();
        public abstract FieldElement MultiplicationInvert();
        public abstract FieldElement MultiplyBy(FieldElement another);
        public abstract FieldElement One; //Multiplication neutral element
        public abstract FieldElement Zero; //Addition neutral element
    
        public FieldElement Subtract(FieldElement another)
        {
            return this.Add(another.SumInvert());
        }
    
        public FieldElement Divide(FieldElement another)
        {
            return this.MultiplyBy(another.MultiplicationInvert());
        }
        public virtual FieldElement Power(uint b)
        {
            if (b == 0)
                return this.One;
            else
            {
                FieldElement result = this;
                for (int i = 0; i < b - 1; i++)
                    result = result.MultiplyBy(result);
                return result;
            }
        }
    }
    

    然后我这样定义实数:

    public class RealNumber : FieldElement
    {
        public double Value { get; set; }
    
        public RealNumber(double value)
        {
            this.Value = value;
        }
        public override FieldElement Power(uint b)
        {
            return new RealNumber(Math.Pow(Value, b));
        }
        public override FieldElement Add(FieldElement another)
        {
            if (another.GetType() != typeof(RealNumber)) //Ugly typecast to enforce type-safety
                throw new ArgumentException("RealNumber expected in Add method");
    
            return new RealNumber(Value + (another as RealNumber).Value);
        }
    }
    

    然后我可以定义对字段元素的通用操作(通过使用泛型):

    public class FieldOperations<T> where T: FieldElement 
    {
        public T Add(T a, T b)        
        {
            return a.Add(b) as T;
        }
        public T Multiply(T a, T b)
        {
            return a.MultiplyBy(b) as T;
        }
        public T Subtract(T a, T b)
        {
            return a.Subtract(b) as T;
        }
        public T Divide(T a, T b)
        {
            return a.Divide(b) as T;
        }
        public T Power(T a, uint b)
        {
            return a.Power(b) as T;
        }   
    }
    

    我会在代码中这样使用它:

    public class TestFieldOperations
    {
        public static void TestAddRealNumbers()
        {
            FieldOperations<RealNumber> operations = new FieldOperations<RealNumber>();
            RealNumber a = new RealNumber(0.5);
            RealNumber b = new RealNumber(0.7);
            RealNumber c = operations.Add(a, b);
            RealNumber d = operations.Power(c, 3);
        }
    }
    

    同样,我可以在向量上使用 FieldOperations,在 InvMatrix 上使用 FieldOperations...

    能够以类型安全和面向对象的方式抽象字段操作的概念可能非常强大:能够在同一抽象级别处理数字、向量和(可逆)矩阵算术。

    【讨论】:

    • 这是如何——或者它——如何处理覆盖操作的?假设定义了一个求幂运算符 public T Power(T a, unsigned int b),如果 b 为 0,则返回 T.one,否则返回 a.Multiply(Power(a, b-1))。当我有FieldOperations&lt;SomeOtherField&gt; 时,我希望它运行。但我想要一个不同的函数来为RealNumbers 覆盖它,这样会更有效率。这可能吗?
    • 编辑了上面的原始答案。这不是您正在寻找的。这只是一种解决方法。函数 Power 是抽象定义的,然后为 RealNumber 重新定义。
    猜你喜欢
    • 2016-04-02
    • 2019-08-02
    • 1970-01-01
    • 1970-01-01
    • 2014-05-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-08-24
    相关资源
    最近更新 更多