干净的方式来尊重 DRY 的条件

Clean way to respect DRY for conditions

我在打字稿中得到了这段代码(尽管语言并不重要):

let name = '', parentId = '';
if (obj instanceof Service) {
    name = obj.name;
} else if (obj instanceof Method) {
    name = obj.name;
    parentId = this.generateUUID(obj._parentService);
} else if (obj instanceof Argument) {
    name = obj.name;
    parentId = this.generateUUID(obj._parentMethod);
}

我可以用 case 语句做同样的事情,但这不会改变问题:我重复了 name = obj.name; 3 次

所以我可以将代码更改为:

let name = '', parentId = '';

if(obj instanceof Service || obj instanceof Method || obj instanceof Argument)
    name = obj.name;

if (obj instanceof Method) {
    parentId = this.generateUUID(obj._parentService);
} else if (obj instanceof Argument) {
    parentId = this.generateUUID(obj._parentMethod);
}

但是我有一个我不太喜欢的条件重复..

有没有办法做到既不重复又可读性好?


这是我的问题的一个最小可重现示例:

class A {name:string=''}
class B {name:string=''; parentA: A = new A()}
class C {name:string=''; parentB: B = new B()}

function hash(s: string): string{
  return '' + s.split("").reduce(function(a,b){a=((a<<5)-a)+b.charCodeAt(0);return a&a},0);              
}

function generateUUID(obj: A | B | C) {
    let name = '', parentId = '';

    if (obj instanceof A) {
        name = obj.name;
    } else if (obj instanceof B) {
        name = obj.name;
        parentId = generateUUID(obj.parentA);
    } else if (obj instanceof C) {
        name = obj.name;
        parentId = generateUUID(obj.parentB);
    }

    return hash(parentId+name);
}

const a = new A();
a.name = 'a';

const b = new B();
b.name = 'b';
b.parentA = a;

const c = new C();
c.name = 'c';
c.parentB = b;


console.log(
    generateUUID(c)
);

您将无法始终避免所有重复。 DRY,作为一个原则,就是摆脱不必要的重复,但并不限制你在必要时不能重复自己的情况。因此,将自我重复保持在合理的最低限度应该是一种妥协。我建议如下:

if(obj instanceof Service || obj instanceof Method || obj instanceof Argument) {
    name = obj.name;
    if (obj.instanceof Method) {
        parentId = this.generateUUID(obj._parentService);
    } else if (obj instanceof Argument) {
        parentId = this.generateUUID(obj._parentMethod);
    }
}

您可以通过实施基础 class/interface 来进一步增强这一点,确保 obj 是这样一个实例并为它实施 generateUUID 以及所有 类 扩展它,因此您将不需要使用级别的内部条件。

既然您已经使用了 类,那么将 generateUUID 放入其中可能是合理的。

function hash(s: string): string {
  return "" + s.split("").reduce((a, b) => {
    a = ((a << 5) - a) + b.charCodeAt(0);
    return a & a;
  }, 0);
}

class A {
  name: string = "";

  generateUUID() {
    return hash(this.name);
  }
}

class B {
  name: string = "";
  parentA: A = new A();

  generateUUID() {
    return hash(this.parentA.generateUUID + this.name);
  }
}

class C {
  name: string = "";
  parentB: B = new B();

  generateUUID() {
    return hash(this.parentB.generateUUID + this.name);
  }
}

const a = new A();
a.name = "a";

const b = new B();
b.name = "b";
b.parentA = a;

const c = new C();
c.name = "c";
c.parentB = b;

console.log(
  c.generateUUID()
);