Чистый способ уважать DRY за условия - PullRequest
3 голосов
/ 16 апреля 2020

У меня есть этот кусок кода в машинописи (хотя язык на самом деле не имеет значения):

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)
);

Ответы [ 2 ]

3 голосов
/ 16 апреля 2020

Вы не сможете все время избегать дублирования. 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);
    }
}

Вы можете улучшить это, внедрив базовый класс / интерфейс, убедившись, что obj является таким экземпляром, и реализовав generateUUID для него, а также для всех классы, которые расширяют его, поэтому вам не понадобятся внутренние условные выражения на уровне использования.

1 голос
/ 16 апреля 2020

Поскольку вы уже используете классы, может быть разумно добавить 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()
);
...