интерфейс из классов в javascript для удаления пары

#javascript #typescript #interface

#javascript #typescript #интерфейс

Вопрос:

Я пытаюсь понять первую часть этого руководства — часть интерфейса, а не часть IOC. Я думаю, что формулировка довольно запутанная, поэтому просто хотел получить более четкое объяснение.

Эта цитата в руководстве — это то, что я не понимаю.

Поэтому, чтобы наш код не был так тесно связан, мы должны выводить зависимости и вместо этого ссылаться на эти интерфейсы.

Я создал пример скрипки точно так же, как в приведенном выше руководстве, используя интерфейсы. https://jsfiddle.net/89w32ajh/13 /

Какую развязку я получаю от примера первого класса к интерфейсу? Помимо интерфейсов, делающих его более контрактным, например, где у вас должно быть то, что требуется интерфейсу в самом классе.

Я просто не вижу развязки, о которой он говорит в своей цитате. Я все еще вызываю new Plant() и new WateringCan() в конструкторе.

 interface IPlant {
    name: string;
}

class Plant implements IPlant {
  public name: string;
  constructor(name: string) {
    this.name = name;
  }
}

interface IWateringCan {
    material: string;
    water (plant: IPlant): void;
}

class WateringCan implements IWateringCan {
  private material: string;
  constructor(material: string){
    this.material = material;
  }
  
  public water(plant: Plant) {
    const str = plant.name   'is been watered by a '   this.material   ' waterign can';
    return str;
  }
}

class Gardener {
    private plant: IPlant;
    private wateringCan: IWateringCan;

    constructor () {
     this.plant = new Plant("Daffodil");
     this.wateringCan = new WateringCan("Steel");
    }

    public waterPlant(): void {
        return this.wateringCan.water(this.plant);
    }
};

const gardner = new Gardener();
gardner.waterPlant();
  

Заранее спасибо за любую помощь.

Ответ №1:

Позже, когда вы рефакторируете код и предоставляете другую реализацию, или когда вы внедряете реализацию, контракт остается тем же, и ваш средство проверки типов сообщит вам, удовлетворяет ли его новая реализация.

Без этого, когда вы вводите конкретную реализацию в качестве типа, как только вы измените реализацию, вы одновременно измените тип, и у вас нет гарантии, что новая реализация удовлетворяет контракту.

Кроме того, когда вы создаете новую реализацию, вы можете реализовать контракт, и вы получаете такие вещи, как «Реализовать все необходимые элементы» и ошибки, пока не выполните контракт.

При использовании только одной конкретной реализации единственная выгода заключается в замене этого компонента (будущий рефакторинг). Если вы перейдете на вводимые компоненты, такие как дополнительные соединители базы данных, тогда вы получите преимущество интерфейсов на основе контрактов.

Позже вы можете создать BigPlant класс, который реализует IPlant и с небольшим рефакторингом поддерживает введенные зависимости. Это так просто, как:

 class Gardener {
    private plant: IPlant;
    private wateringCan: IWateringCan;

    constructor (PlantClass: IPlant) {
     this.plant = new PlantClass("Daffodil");
     this.wateringCan = new WateringCan("Steel");
    }

    public waterPlant(): void {
        return this.wateringCan.water(this.plant);
    }
};
  

На практике вы можете использовать это для таких вещей, как внедрение поставщика базы данных, где вы не знаете или не заботитесь о базовой базе данных — просто поставщик БД реализует необходимый вам контракт.

Таким образом, ваше приложение может поддерживать различные базы данных, а не быть тесно связанным с конкретным поставщиком базы данных.

Комментарии:

1. При использовании только одной конкретной реализации единственное преимущество заключается в замене этого компонента. Какой компонент вы имеете в виду?

2. Все, что указано как зависимость, с использованием интерфейса, а не конкретного типа. В этом случае можно сажать и поливать. Вы можете создать тип BigPlant, который реализует IPlant, и внести одно изменение в код: this.plant = new BigPlant(«Daffodil»); Следующим шагом будет внедрение зависимостей.

3. Хорошо, я понимаю, что вы говорите. Так что, по сути, это то, что я думал, что вы получаете только контракт, а не совсем развязку.

4. Без интерфейса вам пришлось бы изменить тип свойства plant, и вы не смогли бы ввести другой тип в конструктор. Вам пришлось бы расширить сигнатуру типа конструктора типом объединения для каждого конкретного типа, который он может принять.

5. Хорошо, я понимаю, поэтому вы бы создали его как new Gardener (растение); Так что, если бы у вас был BigPlant с тем же контрактом IPlant. Вы могли бы передать это в new Gardener (BigPlant); и это не сломалось бы, как в конкретной настройке?