【问题标题】:How can I not repeat writing similar code?我怎样才能不重复编写类似的代码?
【发布时间】:2021-05-12 02:27:27
【问题描述】:

我有两个非常相似的函数,它们几乎是重复的,只是条件相反。我想遵循 DRY 模式,但我之前在某处读过,将布尔值传递给函数以改变行为是一种不好的做法(因为它难以维护)。我在这里编写干净且不重复的代码的最佳选择是什么?谢谢

def find_upper_tangent(left, right):
    l_idx = get_rightmost(left)
    r_idx = get_leftmost(right)
    upper_tangent_left = False
    upper_tangent_right = False
    prev_slope = get_slope(left[l_idx], right[r_idx])
    while not upper_tangent_left or not upper_tangent_right:
        while not upper_tangent_left:
            # move counter clockwise
            next_slope = get_slope(left[(l_idx - 1) % len(left)], right[r_idx])
            if next_slope < prev_slope:
                l_idx = (l_idx - 1) % len(left)
                prev_slope = next_slope
                upper_tangent_right = False
            else:
                upper_tangent_left = True
        while not upper_tangent_right:
            # move clockwise
            next_slope = get_slope(left[l_idx], right[(r_idx + 1) % len(right)])
            if next_slope > prev_slope:
                r_idx = (r_idx + 1) % len(right)
                prev_slope = next_slope
                upper_tangent_left = False
            else:
                upper_tangent_right = True
    return l_idx, r_idx


def find_lower_tangent(left, right):
    l_idx = get_rightmost(left)
    r_idx = get_leftmost(right)
    lower_tangent_left = False
    lower_tangent_right = False
    prev_slope = get_slope(left[l_idx], right[r_idx])
    while not lower_tangent_left or not lower_tangent_right:
        while not lower_tangent_left:
            # move clockwise
            next_slope = get_slope(left[(l_idx + 1) % len(left)], right[r_idx])
            if next_slope > prev_slope:
                l_idx = (l_idx + 1) % len(left)
                prev_slope = next_slope
                lower_tangent_right = False
            else:
                lower_tangent_left = True    
        while not lower_tangent_right:
            # move counter clockwise
            next_slope = get_slope(left[l_idx], right[(r_idx - 1) % len(right)])
            if next_slope < prev_slope:
                r_idx = (r_idx - 1) % len(right)
                prev_slope = next_slope
                lower_tangent_left = False
            else:
                lower_tangent_right = True
    return l_idx, r_idx

【问题讨论】:

    标签: design-patterns refactoring dry


    【解决方案1】:

    我认为类似的事情应该做同样的计算:

    def find_upper_tangent(left, right):
        return find_tangent(left, right, -1)
    
    def find_lower_tangent(left, right):
        return find_tangent(left, right, 1)
    
    def find_tangent(left, right, shift_val):
        l_idx = get_rightmost(left)
        r_idx = get_leftmost(right)
    
        prev_slope = get_slope(left[l_idx], right[r_idx])
        next_slope = prev_slope
    
        while compare(next_slope, prev_slope) == (shift_val / shift_val):
            # move counter clockwise
            prev_slope = next_slope
            l_idx = (l_idx + shift_val) % len(left)
            next_slope = get_slope(left[l_idx], right[r_idx])
    
        while compare(next_slope, prev_slope) == (shift_val / -shift_val)):
            # move clockwise
            prev_slope = next_slope
            r_idx = (r_idx - shift_val) % len(right)
            next_slope = get_slope(left[l_idx], right[r_idx])
    
        return l_idx, r_idx
    
    def compare(v1, v2):
        return -1 if v1 > v2 else 0 if v1 == v2 else 1
    

    IMO 这比传递标志要好,因为您传递的是有意义的值并用于计算。

    我是怎么到这里的

    由于您要求一种方法,我将尝试描述我是如何得出这个解决方案的:

    1. 简化代码

      • 外部while 循环只运行过一次,因此可以将其删除。这是关键,因为它消除了循环条件变量的一种使用。
      • 然后我们看到每个剩余的while 循环都有一个else 子句,它只设置循环条件变量。相反,我们可以简单地使用if 条件作为循环条件。这消除了对布尔变量的需求并减少了代码路径的数量——这两个都是简化代码的好目标!
      • 现在我们看到需要更改操作顺序。在计算新值之前,我们需要保存next_slope 的值。我们还对新指数进行了两次计算。一次获取斜率,一次保存值。相反,我们可以计算新指数,然后在斜率计算中使用它。
    2. 注意代码中的相似之处

      • 请注意,在两个循环中,我们移动了索引,但方向相反。我们可以添加一个移位值参数并编写代码,使移位的方向即使在相同的值下也会发生变化。
      • 请注意,上下切线计算中左右循环的比较方向不同。为了解决这个问题,我们可以编写一个函数来比较两个事物,如果第一个更大则返回 -1,如果第二个更大则返回 1,如果它们相同则返回 0。
      • 现在我们有了根据我们是在寻找上限还是下限而具有不同符号的移位值,我们可以使用它来翻转while 条件的方向。

    我尚未验证此解决方案是否有效 - 如果您想发布一些测试数据和预期结果,那就太好了!

    【讨论】:

    • 因为我没有包含代码的上下文,所以重构是关闭的(它是合并两个凸包的一部分,如果你仔细观察,外部的 while 循环会运行不止一次,我想它不是很可读),但我对如何实现它有一个很好的想法。谢谢
    猜你喜欢
    • 1970-01-01
    • 2017-08-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-11-30
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多