首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >类使用依赖于变量参数的方法初始化,但该变量在应用程序的大部分部分都是常量。

类使用依赖于变量参数的方法初始化,但该变量在应用程序的大部分部分都是常量。
EN

Software Engineering用户
提问于 2016-07-19 14:15:35
回答 2查看 229关注 0票数 3

我正在寻求关于如何设计以下场景的建议:

我有一个三维向量类,条目是double类型的.如果两个向量的对应元素差小于给定的公差,例如10^(-10),我希望它们被认为是相等的。

(代码示例在C#语法中与伪代码混合使用。)

代码语言:javascript
复制
public class Vector
{
    double x, y, z;

    public bool TolEquals(Vector other)
    {
        return ((|x-other.x| < 10^(-10))  // absolute value of difference
             && (|y-other.y| < 10^(-10))  // must be small enough
             && (|z-other.z| < 10^(-10)));
    }
}

我需要一定的灵活性,因为其他人可能希望使用比10^(-10)更多的容忍度值。

这意味着,我需要将公差值以某种方式合并到我的等式检查方法中,例如:

代码语言:javascript
复制
public bool TolEquals(Vector other, double tolerance)
{
    return ((|x-other.x| < tolerance)
         && (|y-other.y| < tolerance)
         && (|z-other.z| < tolerance);
}

但我知道,在我的整个申请,容忍将是不变的。我不想写

代码语言:javascript
复制
v1.TolEquals(v2, tolerance)

每次我检查是否相等,因为它不是很容易读,因为打字可以很容易发生。

另一个想法是将tolerance存储为Vector类的成员,并将其设置在Vector的构造函数中。那么TolEquals方法只需要一个参数:

代码语言:javascript
复制
public class Vector
{
    double x, y, z;
    double tolerance;

    public Vector(double x, double y, double z, double tolerance)
    {
        this.x = x;
        this.y = y;
        this.z = z;
        this.tolerance = tolerance;
    }

    public bool TolEquals(Vector other)
    {
        return ((|x-other.x| < tolerance)
             && (|y-other.y| < tolerance)
             && (|z-other.z| < tolerance));
    }
}

但是,使用我的代码的人可能会意外地创建具有不同公差的两个向量vw,并从v.TolEquals(w)w.TolEquals(v)那里得到不同的答案。这也不应该发生。

我可能迟早会向我的Vector类中添加一些静态方法,这些方法以几个向量作为输入,并与它们一起进行一些涉及TolEquals的计算。所以我需要确保所有的向量都使用相同的容差值。

我正在寻找一种解决方案,允许我在程序中的某个地方定义tolerance,在Vector类之外,然后所有向量都使用该tolerance作为他们的TolEquals。而且我希望能够在运行时更改tolerance (现在不需要它,但以后可能需要它),因此所有的向量都使用新的值。但可能是使用我的代码的人需要两个不同的容差值共存。他将有两组不同的载体,使用不同的容忍度值,但这两组不相互作用。

所以静态字段tolerance也是不可选的。

我还将编写一个matrix类,也许还会编写一些类似于TolEquals的类,因此解决方案不应该局限于我的Vector类。

有什么想法吗?

编辑:

在接受答案的启发下,我想提出我的最终解决方案(在C#中),并发表一些评论。所有的信息都是在被接受的答案中给出的,但是我花了一些时间来处理它,所以我会在这里对它做一些改进。我决定在泛型向量类中使用静态字段来实现它:

代码语言:javascript
复制
public interface ISpace { double TOL(); }

public class ZeroTolSpace : ISpace { public double TOL() => 0; }
public class Tol10Space : ISpace { public double TOL() => 1E-10; }
// Others can easily write new classes for other tolerance values.

public class Vector<T> where T: ISpace, new()
{
    private double x, y, z;
    public static double? tol = null; // Changeable at runtime (if really needed)!

     public Vector(double x, double y, double z)
     {
         this.x = x; this.y = y; this.z = z;
         tol = tol ?? (new T()).TOL(); // Since tol is static, the new-operator
                                       // gets called only once, minimzing overhead.
     }

    public bool TolEquals(Vector other)
    {
         return ((Math.Abs(x-other.x) < tol)
              && (Math.Abs(y-other.y) < tol)
              && (Math.Abs(z-other.z) < tol));
    }

}

然后在Main方法中我们可以这样做:

代码语言:javascript
复制
        Vector<ZeroTolSpace> v1 = new Vector<ZeroTolSpace> (0, 0, 0);
        Vector<ZeroTolSpace> v2 = new Vector<ZeroTolSpace>(1E-11, 1E-11, 1E-11);
        v1.TolEquals(v2)); // false since _tol is 0

        Vector<Tol10Space> w1 = new Vector<Tol10Space> (0, 0, 0);
        Vector<Tol10Space> w2 = new Vector<Tol10Space> (1E-11, 1E-11, 1E-11);
        w1.TolEquals(w2)); // true since tol is 1E-10

        v1.TolEquals(w2)); // compile error: types do not match

矩阵和其他依赖于公差的类可以以同样的方式实现。

EN

回答 2

Software Engineering用户

回答已采纳

发布于 2016-07-19 14:42:49

但我知道,在我的整个申请,容忍将是不变的。

这有点可疑,因为这种容忍通常是非常特定于算法的。我不得不面对很多痛苦,因为有人认为他们可以在任何地方使用持续的宽容来逃避痛苦。

但假设你真的想要这个,我可能会这样做:

代码语言:javascript
复制
public class Space {
    public Space(double tolerance);


    public Vector vector(double x, double y, double z);
    public Matrix matrix(...);
}

因此,您创建了一个Space类,它提供了创建向量的唯一方法。不能组合由不同空间类创建的向量。在特定的应用程序中,您只需创建一个空间常量,它定义了所使用的容忍度。

我希望能够在运行时改变容忍度(现在不需要它,但以后可能需要它),从而导致使用新值的所有向量。

不,你没有。在运行时改变容忍度会导致痛苦和痛苦。如果您的代码需要在不同的情况下具有不同的公差,那么您确实希望传递一个参数。

现在,真的,如果我们可以使用泛型,那就更好了:

代码语言:javascript
复制
Vector<MySpace>

然后在MySpace上有一个静态方法定义公差。然后,类型系统可以验证您从来没有混合不同类型的向量。唉,这超出了某些编程语言的范围,所以您可能会也可能无法使用它。

==编辑==

C++可以通过模板很好地完成这一任务:

代码语言:javascript
复制
struct MySpace {
   public static double tolerance = 0.000001;
}

template<typename T>
class Vector {
    Vector(double x, double y, double z);

    // We can refer to T::tolerance
}

// I can use Vector<MySpace> to refer to vectors with a particular
// space, and have the type system enforce that.

但这取决于这样一个事实,即C++模板可以自由引用其类型参数中的元素。但其他语言往往缺乏这种能力。

在C#中,您可以做类似的事情(我不做C#,但我相信这是有效的)

代码语言:javascript
复制
interface Space {
   double tolerance();
}

public class MySpace extends Space {
   double tolerance() {
       return 0.000001;
   }
}

public class Vector<T> where T: Space, new() {
   public Vector(double x, double y, double z);

   // I can get my tolerance via (new T()).tolerance()
   // We hope that the optimizer can get rid of the overhead.
}

但是在Java中,这是行不通的,因为我们不能做new T。我们可以这样做:

代码语言:javascript
复制
class Vector<T extends Space> {
    Vector(T t, double x, double y, double z);

    // t.tolerance() will be the tolerance.    
}

然后按照惯例,始终通过单例子类创建Space的实例。

===

关于Java解决方案的更多细节

在图书馆:

代码语言:javascript
复制
public interface Space {
    double tolerance();

    public static <T extends Space> double toleranceForSpace(Class<T> spaceClass) {
    return spaceClass.newInstance().tolerance();
}
}

public Vector<SpaceType> {
    Vector(Class<SpaceType> spaceType, double x, double y, double z);

    // call Space.toleranceFor(spaceType) to get the tolerance
}

在非图书馆代码中:

代码语言:javascript
复制
class MySpace extends Space {
   double tolerance() { return 0.1; }
}


Vector<MySpace> space = new Vector<>(MySpace.class, 2.3, 4.5, 6.7);
票数 4
EN

Software Engineering用户

发布于 2016-07-19 20:24:44

在这里,可选参数可以很好地工作。

代码语言:javascript
复制
public class Vector {
  public static readonly double DefaultTolerance = 0.0001; // or whatever.

  public bool Equals(Vector other, double? tolerance = null) {
    tolerance = tolerance ?? DefaultTolerance;
    // go about your business
  }
}

// later
w.Equals(v);
w.Equals(v, 0.001);

由于公差适用于运算,而不是数据,所以向量本身不拥有它是很好的。

票数 1
EN
页面原文内容由Software Engineering提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://softwareengineering.stackexchange.com/questions/325213

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档