Здесь есть замечательные ответы на эти вопросы, которые вовлекают во всевозможные подробные сведения о интерфейсах и слабосвязанный код, инверсию управления и т. д. Есть несколько довольно острых дискуссий, поэтому я хотел бы воспользоваться возможностью немного разобраться в том, почему интерфейс полезен.
Когда я впервые начал работать с интерфейсами, я тоже был смущен об их значимости. Я не понимал, зачем вам это нужно. Если мы используем такой язык, как Java или C #, у нас уже есть наследование, и я рассматривал интерфейсы как более слабую форму наследования и мысли «зачем беспокоиться»? В некотором смысле я был прав, вы можете думать о интерфейсах как о какой-то слабой форме наследования, но помимо этого я, наконец, понял их использование в качестве языковой конструкции, считая их как средство классификации общих черт или моделей поведения, которые были представлены потенциально много несвязанных классов объектов.
Например, скажем, у вас есть игра с SIM-картой, и у вас есть следующие классы:
class HouseFly inherits Insect {
void FlyAroundYourHead(){}
void LandOnThings(){}
}
class Telemarketer inherits Person {
void CallDuringDinner(){}
void ContinueTalkingWhenYouSayNo(){}
}
Очевидно, что эти два объекта не имеют ничего в общий с точки зрения прямого наследования. Но вы могли бы сказать, что они оба раздражают.
Предположим, что в нашей игре должно быть какое-то случайное вещь , которая раздражает игрока, когда они едят обед. Это могут быть HouseFly
или Telemarketer
или оба, но как вы можете использовать обе функции с одной функцией? И как вы просите каждый из разных типов объектов «делать свою раздражающую вещь» таким же образом?
Ключом к пониманию является то, что как Telemarketer
, так и HouseFly
имеют общее слабо интерпретируемое поведение даже несмотря на то, что они не имеют ничего общего с их моделированием. Итак, давайте создадим интерфейс, который оба могут реализовать:
interface IPest {
void BeAnnoying();
}
class HouseFly inherits Insect implements IPest {
void FlyAroundYourHead(){}
void LandOnThings(){}
void BeAnnoying() {
FlyAroundYourHead();
LandOnThings();
}
}
class Telemarketer inherits Person implements IPest {
void CallDuringDinner(){}
void ContinueTalkingWhenYouSayNo(){}
void BeAnnoying() {
CallDuringDinner();
ContinueTalkingWhenYouSayNo();
}
}
Теперь у нас есть два класса, каждый из которых может раздражать по-своему. И им не нужно выводить из одного базового класса и обладать общими присущими характеристиками - им просто нужно удовлетворить контракт IPest
- этот контракт прост. Вам просто нужно BeAnnoying
. В этой связи мы можем моделировать следующее:
class DiningRoom {
DiningRoom(Person[] diningPeople, IPest[] pests) { ... }
void ServeDinner() {
when diningPeople are eating,
foreach pest in pests
pest.BeAnnoying();
}
}
Здесь у нас есть столовая, в которой принимают несколько посетителей и несколько вредителей - обратите внимание на использование интерфейса. Это означает, что в нашем маленьком мире членом массива pests
может быть объект Telemarketer
или объект HouseFly
.
Метод ServeDinner
вызывается при подаче обеда и наши люди в столовой должны есть. В нашей маленькой игре, вот когда наши вредители выполняют свою работу - каждый вредитель инструктируется быть раздражающим через интерфейс IPest
. Таким образом, мы с легкостью можем раздражать как Telemarketers
, так и HouseFlys
в каждом из своих способов - мы заботимся только о том, что у нас есть что-то в объекте DiningRoom
, являющемся вредителем, нам все равно что это такое, и они не могли иметь ничего общего с другими.
Этот очень надуманный пример псевдокода (который тянулся намного дольше, чем я ожидал) просто предназначен для иллюстрации того, что, наконец, включило свет для меня с точки зрения того, когда мы могли бы использовать интерфейс. Я заранее извиняюсь за глупость примера, но надеюсь, что это поможет в вашем понимании. И, конечно же, другие опубликованные ответы, которые вы получили здесь, действительно охватывают диапазон использования интерфейсов сегодня в шаблонах проектирования и методологиях разработки.
Я думаю, что вы ищете:
const {corn, peas} = vegetableColors;
Live on REPL Вавилона
Если правый Pointy , что вы спрашиваете, как это сделать без , зная имена corn
и peas
, вы не можете с назначением destructuring.
Вы можете в глобальном масштабе только, используя цикл, но я уверен, что вы не хотите делать это в глобальной области. Тем не менее, на всякий случай:
// I'm sure you don't really want this, just being thorough
Object.keys(vegetableColors).forEach((key) => {
Object.defineProperty(this, key, {
value: vegetableColors[key]
});
});
(Throw enumerable: true
там, если вы хотите, чтобы эти псевдо-константы были перечислимыми.)
Это работает в глобальной области видимости, потому что this
относится к глобальному объекту.
this
:-) – Bergi 9 August 2015 в 19:51with
, и я никогда не буду использовать это, но это именно то, о чем я прошу ... Дерьмо! О чем я только думал!? :П – Resist Design 9 August 2015 в 19:51with
, если хотите, он не будет удален из языка (в основном для обратной совместимости проблемы, хотя). – Bergi 29 May 2016 в 23:01with
не является «решением», imo, потому что теперь вы должны обернуть весь свой модуль вwith
и добавить отступ уровня, что еще хуже, чем добавление имени объекта для каждого вызова функции или импорт всего по имени вверху с деструктурированием. – Jonah 29 May 2016 в 23:04