Понять интерфейсы

За несколько дней перечитал кучу статей. Там 100 раз о полезности интерфейсов. Но я никак не пойму, как они реально помогают (реализация множественного наследования и описание логики объектов не в счет).

До чего я дошел.

Вот например.
Есть клиент, которому нужно платить за что-то.
Платить можно несколькими способами, где процесс оплаты разный.
Например, картой, пайпал, вебмани.

Есть интерфейс

interface Topay {
	void pay();
}

Есть несколько классов, которые реализуют этот интерфейс

Class card implements Topay{
	void pay() {}
}
 
Class paypal implements Topay{
	void pay() {}
}

Class webmoney implements Topay{
	void pay() {}
}

Есть класс клиент

class Client {
	Topay payment;

	//тут я понимаю, что могу создать 
	payment = new card или paypal или webmoney;
}

Но что с того? Что мне дало использование интерфейса?

Підписуйтеся на Telegram-канал «DOU #tech», щоб не пропустити нові технічні статті

👍ПодобаєтьсяСподобалось0
До обраногоВ обраному1
LinkedIn

Найкращі коментарі пропустити

Ещё могу тебе предложить подумать об интерфейсе не как абстракции в коде, а как о том откуда они туда пришли — из реального мира. Вот просто подумай что значит интерфейс USB или bluetooth. Что знает компьютер о подключаемых через USB устройствах. Есть ли там только реализуемые действия или проперти тоже (например, вольтаж?), можно ли выделить абстрактный класс, чтобы расшарить его со всеми производителями всех юсб устройств? Будет ли вообще у них что-то общее в реализации?

Дозволені теги: blockquote, a, pre, code, ul, ol, li, b, i, del.
Ctrl + Enter
Дозволені теги: blockquote, a, pre, code, ul, ol, li, b, i, del.
Ctrl + Enter

Использование интерфейса дало тебе расширяемость твоего (или чужого) кода. Рассмотрим пример, когда класс Client у тебя закрыт. Ну не знаю, спрятан в node_modules где-то. То есть, доступа у тебя к нему нет, а там по дефолту полю payment присвоен инстанс класса Card(). Да и само поле типизированно под калсс Card. То есть, где-то внутри модулей, к котоырм ты не имешь доступа для редкактирования, находится класс Client. У него есть вот такая реализация — paymant: Card = new Card(). А тебе нужно поменять способ оплаты, как ты это сделаешь? Залезть внутрь класса ты не можешь. Присвоить полю payment инстасс WebMoney тоже, поскольку поле ожидает тип Card. Все, нет расширяемости. Конечно, ты мог бы отнаследовать класс WebMoney от класса Card и переопределить метод pay() на другое поведение. Однако, лучше избегать подобных практик и забыть про наследование, используя его только по отношению к абстрактным классам. Для этого и используются интерфейсы, для расширяемости. Если поле payment ожидает объекты типа Topay, то ты без проблем можешь создавать абсолютно разные по функционалу способы оплаты, котоыре следуют интерфесу Topay и присваивать их инстансы полю payment. Ты избавился от зависимости от прямой реализации и зависишь только от абстракции. Прошу заметить, что по второму принципу SOLID все твои классы должны быть закрыты для изменений, но открыты для модификаций. Использование интерфейсов помогает четко следовать этому принципу.

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

Вот пару примеров из моей практики, это было на C#, но думаю суть +/- похожая.
1) Необходимость при старте проекта в зависимости от окружения, на котором идет билд регистрировать в контейнере управления зависимостями разные классы на единый интерфейс. Приложение в итоге будет работать с интерфейсом, однако на разных окружениях будут разные фактические реализации.

2) Передача коллекций, поддерживающих IEnumerable(сам простой C# интерфейс, поддерживающийся всеми коллекциями) через параметры методов, там мог быть и list, и array, и что угодно. Мы не знаем, но можем делать из него выборки.

3) Слабая связность компонентов внутри модуля. ru.wikipedia.org/...​зность_(программирование Тут тебе и бОльшая простота поддержки кода, заменяя реализацию класса в 1 месте вместо замены по всему коду, связь компонентов через узкое и понятное место — интерфейс.

Если простым языком, то интерфейс это то, что описывает что должна уметь делать определенная сущность, и не важно чем она есть (это выражают классы).
Например есть интерфейс IComparable, он описывает способность уметь себя сравнивать, и не важно какой класс скрыт за интерфейсом.
Так же и с интерфейсом ITopay. У тебя есть метод Pay? Ок. Остальное неважно.

Не успел прочитать все комменты, может кто уже и написал где:
Интерфейс — это контракт на поведение.
Он позволяет уменьшить связанность классов: твой класс Клайент теперь ничего не знает о реальной реализации метода пей, он знает что при его вызове произойдет этот самый пеймент. Ему не нужно знать подробностей( куда будет платиться, что еще будет вызываться для реализации платежа и т.д.)
И вот использование интерфейса дало тебе возможность гораздо легче вносить изменения: тебе надо заменить метод пеймента на ПейментЧерезКассуВБанке() и тогда тебе не нужно будет ничего менять в клайенте.
Тестировать такое тоже гораздо легче.
А вот применение в твоем примере не очень:

//тут я понимаю, что могу создать
payment = new card или paypal или webmoney;

надо заменить на какой-нибудь @Autowired этого же интерфейса и IoC контейнер сам найдет и вставит тебе текущую реализацию.
Тут рекомендую больше почитать про инверсию заисимостей.
P.S. Выгода от такого подхода почти не видна на таких маленьких примерах.
Задумайся если у тебя будет 200 классов большинство которых будет знать друг о деталях реализации поведения друг друга и тебе нужно будет внести изменения в один из них — сколько классов в итоге реально затронут изменения?
И та же ситуация среди классов, где они взаимодействуют друг с другом через интерфейсы, даже не подозревая как там у остальных реализовано это поведение.

Интерфейсы — часть контракта, минимально необходимая технически в мэйнстрим языках, где они или их аналоги есть, но обычно недостаточная. Грубо, то, что метод add интерфейса принимает параметром экземпляр этого же типа и тот же тип возвращает, ещё обычно не весь контракт. Банально в контракт может входить иммутабельные должны быть экземпляры классов или должен возвращать себя же изменённого. Не говоря о том, что имплементация вообще должна иметь что-то общее с добавлением или сложением.

а мои примеры об способах оплаты, рыбаке, авторизации разве не с той же оперы?

Начни с хаскеля, если ооп не заходит может функиональщина зайдет

Новачку не одразу зрозуміло нащо паритися із відокремленням реалізації взагалі. Написав щось, працює — так нащо вся ця високотеоретизована муть, про яку майже завжди кажуть із пихатими обличчями))

Але якщо дивитись на програму не на як написав и забув, а як на щось, що буде багато разів змінюватися (а воно буде!!), то стає зрозуміло, що зміни робити краще, якщо частини системи легко и зрозуміло відокремлюються від всього іншого. З інтерфейсу легко щрозуміти як саме частини системи пов‘язані та взаємодіють. І тоді легше та безпечніше змінювати систему, та взагалі ії розуміти.

В цьому аспекті стає зрозуміло, нащо взагалі ООП, інтерфейси, IoC, DI, solid, etc...

нащо взагалі ООП, інтерфейси, IoC, DI, solid, etc...

Ага, и потом фабрики фабрик бинов компонентов моделей, так что чам черт ногу сломит, и банальный код скопипейзеный на 3 метода гораздо легче читать и понимать.

Понять и простить)))

Соррі, чукча писатель)))

Всем спасибо за отклики. Очень много полезных мыслей тут прозвучало.

Хочу немного подытожить.
Поделится мыслями с Вами.
Получить обратную связь по поводу своих мыслей.

Что я понял по вопросу для чего нужны интерфейсы:
1. Скрыть реализацию и дать только готовую «кнопку», которая делает, что нужно.
2. Абстрагировать какую-то возможность объекта, что-то делать. Например «Платить», «Передвигаться», «Атаковать» без указания и реализации подробностей.
3. Дать этой возможности полиморфности (принимать разные формы). Например «Платить» — картой, вебмани, пайпал; «Передвигаться» — ходить, летать, ползать; «Атаковать» — кусать, бить рукой, стрелять.
4. Реализовать в Java множественное наследование.

2. В этом коде оправдано использован интерфейс?

interface IAut {
int login();
}

class LoginPass implements IAut {
int login() {
return token=query(select token )
}
}

class SMS implements IAut {
int login() {
return token=device.getsms(id);
}
}

Class Client(IAut aut) {
aut.login();
}

В контексте Java префикс I был вредным советом. Так никто не делает. Это из мира .NET.

Ну не совсем никто, так делали даже ещё до появления .NET и продолжают делать сейчас. Єто лишь соглашения проекта или компании.

Ну, не совсем. Интерфейс это «обещание». Нужен чтобы упростить код, убрать повторения.

К примеру у тебя есть endpoint, где ты не знаешь какой класс у тебя будет подан при вызове, но знаешь какие методы (функции) тебе внутри надо вызывать. Тогда интерфейс полезен. Ты ведь не париться что внутри.
В твоём примере объявления правильные, но смысла в этом нет.не уверен то ты понял зачем в этом примере интерфейс. Попробуй написать код который использует то что ты написал

зачем в этом примере интерфейс

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

как тогда сделать без интерфеса эту задачу так же гибко?

Приведите пример небольшого задания, где интерфейс нужен
спасибо!

самый простой пример где интерфейс необходим:
Strategy Pattern. К примеру у тебя есть орк, у которого есть руки. И он может что-то делать с тем что у него в руках, а в вот что конкретно он не знает: это может быть «удар мечом», «рубка дров» или «полить цветы». Зависит от предмета в руке, но как программист, который понятия не имеет что орк возьмет, и когда отложит обратно, мы пишем интерфейс InteractableEquipment и добавляем его ко всему что можно взять в руки и что можно в руках использовать. Когда добавляем новый инструмент «для копания ям», то нам уже не нужно менять код в орке.

Почему интерфейс вместо класса? Допустим что предмет может быть «пазлом», т.е. у него есть InteractableEquipment, MagicEquipment, ComposedEquipment, и т.д. Вся экипировка будет иметь функцию «надеть», вот только если у нас 3 разных реализации при одинаковом объявлении, возникает беда. А если объявления в интерфейсах одинаковые, то реализация работает на все интерфейсы.

Но это так, мелочи. Для понимания что интерфейсы нужны.

почему к моему примеру с авторизацией не нужно применять интерфейс?
есть орк (есть клиент)
может брать в руки предмет (он может авторизоваться)
берет разные предметы:меч, сокира, ведро с водой (разные способы авторизации:логин-пароль, телефон-смс, apiFacebookAut)
при добавлении авторизации по BankID мне класс Client менять тоже не нужно

Так тебе там и нужен интерфейс..
Ты остановился перед самым интересным.

payment = new card или paypal или webmoney;

paymentProcessor.process(payment);

И paymentProcessor точно знает, что он может из payment взять сумму, отправить платеж, проверить баланс, взять комиссию, записать в лог от кого, и кому. И ему безразлично, card там, paypal или webmoney.
И тебе не нужно писать писать CardPaymentProcessor, PayPalPaymentProcessor, WebmoneyPaymentProcessor. И добавление новой платежной системы для тебя будет простым, без переписывания всего что идет после реализации интерфейса.

Потому что надо читать полностью: попробуй написать код, который с этим работает

оно когда один метод в интерфейсе не сильно «интересно»

В ООП что-то сложнее интерфейсов в понимании есть?

выбор имен для всего этого зоопарка

Да. Дизайн всего того, что пишешь типа-в-ооп-парадигме.

ООП не об интерфейсах
Да, есть вещи сложнее: классы и почему нельзя оставлять переменные внутри public, но все таки можно.
Если касается джавы, то зачем нужны объекты, если есть статические методы? (И почему они таки не нужны)

Если касается джавы, то зачем нужны объекты, если есть статические методы? (И почему они таки не нужны)

Ты топикстартеру еще Бугаенка почитай посоветуй :)

Ок.
Давайте еще так.
Кому не сложно.
Сформулируйте задание, в котором нужно применить интерфейс и он действительно проще решит задачу.
Спасибо!

Начни писать юнит тесты под любой более-менее проект — поймешь.

Да легко. Вот ты с клиентом обсуждаешь, чего делать, он хочет сразу API для интеграции и зафиксировать. Ты пишешь интерфейсы, дальше реализуешь методы тогда, когда на них выделяют деньги. Или передаешь их реализовать джуну за 200баксов в месяц. Или подрядчику. И все работает.

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

Воспринимай это как соглашения на будущее.

Вроде это только один из возможных вариантов использования

Что бы научиться правильно использовать интерфейсы нужно применять подход когда класс не может вызвать другой класс — а только интерфейс!
Это сразу решает массу вопросов:
— Класс легко протестировать в изоляции подложив моки.
— Класс прекрасно укладывается в контейнер зависимостей и не заботится откуда взять нужные реализации.
— В интерфейсе есть только то, что нужно классу, который его использует и нету лишних членов «на все случаи жизни» (принцип разделения интерфейсов).
— Чётко понятно в какой момент жизни класса ему нужен интерфейс: постоянно или временно.
— Понятно какие интерфейсы представляют модели данных (состояние), а какие — процессы (не хранят состояние).
Общий принцип: открываем интерфейсы, но скрываем реализацию! В идеале паблик классов вообще не должно быть.

Это скорее будет злоупотреблением интерфейсами, а не правильным их использованием.

Я пишу код класса «Клиент».
Кто-то пишет код классов авторизации: «LoginPass», «SMS», «BankID», «FacebookAut»
Над нами есть кто-то главный (архитектор, тимлид), кто сказал мне
Клиент должен иметь возможность авторизоваться разными способами
Я пишу в коде
Class Client(IAut aut) {
aut.login();
}
я указываю IAut aut так как не знаю сколько и каких будет вариантов авторизации, но знаю что там будет метод login() {
return token;
}
который вернет мне token. где он его выдернет и как я не в курсе. он просто мне нужен этот токен.

Другой разработчик пишет классы авторизации.
Ему их сказали реализовать для интерфейса interface IAut {
int login();
}

class LoginPass implements IAut {
int login() {
return token=query(select token )
}
}

class SMS implements IAut {
int login() {
return token=device.getsms(id);
}
}

За счет использования интерфейса устанавливается контракт между двумя разработчиками и структуре дается гибкость в виде менее проблемной добавлении нового метода авторизации. Свойства авторизоваться абстрагируется.

Представьте себе панель управления. И там есть кнопки — «Запуск», «Стоп», «Быстрее».
Кнопки — просто куски пластика с подписями.
Соответственно, когда пишем код, который представляет такую панель, если писать максимально просто — у нас получится монтажная плата и 3 места, где можно замкнуть контакты. Например, тут вот подходит 2 проводка, или 3, или 10 и если их замкнуть — произойдёт «Запуск».
Можно всё и так оставить, тот, кто будет работать с вашей панелью — разберётся, где что. А можно дописать интерфейс, чтобы получились 3 кнопки. Тогда те, кому нужно быстро, просто будут жать ваши кнопки, не думая над их реализацией, а те, кому нужно дотошно, те приподнимут кнопку и будут разбираться, сколько и каких контактов эти кнопки замыкают, почему именно такие и что это делает.
Соответственно, сам по себе интерфейс — это панель с такими кнопками, только ещё не установленная на монтажную плату
А абстрактный класс — это эта же панель, но некоторые кнопки запитаны
Полноценный класс — панель, все кнопки работают
Искренне надеюсь, что эта невинная метафора поможет вам)

я не понимаю разницы между монтажной платой и панелью
опишите свою мысль на примере рыбак и средства ловли рыбы (удочка, сетка, мурмышка) или клиент и способы авторизации
спасибо

Да легко)
Чтобы поймать рыбу — мы просим «Рыбак, принеси рыбы». Это — использование интерфейса, мы вот знаем, что у рыбака функция такая, рыбу ловить, хотя не знаем, как он это делает, может, удочкой, может, сетью, может, вообще руками меж корней шарит и ловит)
Здесь, получается, интерфейс — это рыбак, хотя можно реализовать добычу рыбы через «закинуть удочку, забросить сеть, поставить спиннинг». А абстрактный класс — это рыбак, у которого есть удочка, а сеть и спиннинг он не купил)
Само слово — рыбак — это и есть интерфейс, подразумевает, что это человек, который умеет ловить рыбу) Class Fisherman, function getFish().
Соответственно, когда мы пишем класс по оплате мобильного счёта можно написать к нему интерфейс, чтобы человек, который будет с нашим классом работать, не рылся в его реализации, а посмотрел на интерфейс и понял, что наш класс может makePay(money, card account), redeemMoney(card account), lastPayment() и т д. Когда по ту сторону 50 классов, запутанных между собой кучей наследственных связей и в каждом по 20 — 50 функций, публичных, приватных и анонимных, вы будете молиться на то, чтобы для вас по ним написали интерфейс — список рабочих функций для работы со всем этим зоопарком.
Ещё можно интерфейс трактовать как оглавление в любой книге

спасибо!
с оплатой я понял. разделяет один модуль от другого. интерфейс — переходник/соединитель
но с рыбаком Вы меня запутали как-то
можете код своей мысли по рыбаку черкнуть

Имеется в виду, что вам, как покупателю — пофигу, как рыбак там поймал рыбу. Вы просто у него ее запрашиваете. А конкретно поиск места для рыбалки и метода лова — не ваша проблема. В этом случае интерфейс у конкретного обьекта — рыбака — два метода — спросить сколько стоит, забрать. А как уже оно реализовано зависит от конкретного рыбака. Например, он может вообще рыбу покупать у другого. Вас то это не колышит.

А теперь второй класс. Асинхронный рыбак. Спросить цену, запросить рыбу, сросить не готово ли, забрать рыбу.
Причем вообще говоря запросить цену и забрать — интерфейс торговца. Так вы приходите к множественному наследованию. или к вопросу, а нужен ли нам клас рыбака для наших запросов.

Неа, абстрактный класс — рыбак у которого вообще ничего нету.

Попробую зайти с другой стороны.
Есть такая ситуация.

Есть человек.
Он мужчина.
Он может ловить рыбу.
Делать он это может удочкой, сеткой, «телевизором».

Правильно делать так? Стоит тут использовать интерфейс?

1. Создать абстрактный класс «Человек».
2. Создать интерфейс «Ловить рыбу».
3. Создать три класса «Удочка», «Сетка», «Телевизор», которые имплементируют интерфейс «Ловить рыбу».
3. Создать класс «Мужчина» с параметром в конструкторе Class Man (Itofish tofish).
4. Если он захочет ловить мурмышкой, то в класс "Мужчина«изменений не нужно будет вносить. Только добавить класс «Мурмышка» имплементирующий «Ловить рыбу».

Возникает путаница из-за того, что вы сваливаете в кучу абстракции и их имплементации.
Попробуйте «подняться» от конкретных объектов (удочка, сетка, телевизор) к абстракции.
Что нужно человеку — ему нужен некий инструмент, применив который он получит рыбу.
Таким образом получаем абстракцию «инструмент для ловли рыбы» с методом «ловить рыбу», который возвращает рыбу. При этом рыба — это то же интерфейс (потому что поймать можно разную рыбу).

применив который он получит рыбу.

или даже «получит улов». который может оказаться рыбой или сапогом.

берешь 3 объекта:

«Удочка», «Сетка», «Телевизор»

выделяешь общие свойства
сознаешь абстрактный класс с этими свойствами типа:
насадитьПриманку()
забросить()
вытащить()

этот интерфейс будет точать наружу для коммуникации с рыбаком

Интерфейсы это просто один из инструментов для того что б программировать используя понятийное мышление и при таком подходе снижается сильно сложность системы www.psychologos.ru/...​iew/ponyatiynoe-myshlenie

Читай книги, хорошие книги. И совмещай с практикой. И придет понимание

— знаєш, як вони наші абстрактні класи називають?
— ні
— «интерфєйси»
— повбивав би!

абстрактный класс — это интерфейс, который недоделали в класс, потому что не было нужно)

Могу только порекомендовать писать, писать и писать овер9000 кода. Сложнее чем мвц-круд формошлепство и хеловорлды про Pet p = new Cat();
И я не издеваюсь и не стебусь. Преимущества интерфейсов можно прохавать только когда столкнешься с проблемами, для решения которых они и созданы.

Не вижу смысла копировать или пересказывать ничего, т.к. ты сам сказал что прочитал уже 100 статей и это не помогло.

//тут я понимаю, что могу создать
payment = new card или paypal или webmoney;
Но что с того? Что мне дало использование интерфейса?

Автор просто не понял нафига интерфейс, если конкретную реализацию все равно явно инстанциирует в коде. Ему нужно было узнать про DI и фабрику чтобы пазл сложился.

Интерфейс как бы не только для ДИ и фабрики.

Как бы само собой разумеется. Мы же говорим в контексте топика.

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

Интерфейсы реализуют полиморфизм без необходимоси нарушать принцип подстановки Лисков из-за множественного наследования или создания мусорных абстрактных базовых классов (где навалены все методы, а наследуется только часть). Это как бы теория.
На практике польза от интерфейсов проявляется по мере увеличения размера проекта. Интерфейс это другими словами «контракт». Архитектор описывает интерфейсы и это гарантирует, что написаные разными разработчиками классы будут работать вместе. Получать и выдавать данные одних и тех же типов. Это улучшает читаемость кода, уменьшает ошибки и время на согласование. Ценность интерфейсов в их использовании в языках со статической типизацией. Для динамически типизированных языков смысла не имеют.

надо было сразу так и обобщить что в первую очередь имеет смысл при командной работе когада архитерктор «задает эскиз» интерфейсами, а потом кодерки их реализуют в обязательном порядке

Если встанет задача создать класс проплаты то у тебя есть название метода который нужно реализовать обязательно pay(). Красиво смотрится если в webmoney будет proplata() а в paypal pay_m_1() а кроме того эти классы могут быть родительскими и тогда начинается ...

Ещё могу тебе предложить подумать об интерфейсе не как абстракции в коде, а как о том откуда они туда пришли — из реального мира. Вот просто подумай что значит интерфейс USB или bluetooth. Что знает компьютер о подключаемых через USB устройствах. Есть ли там только реализуемые действия или проперти тоже (например, вольтаж?), можно ли выделить абстрактный класс, чтобы расшарить его со всеми производителями всех юсб устройств? Будет ли вообще у них что-то общее в реализации?

я понял, что интерфейс некий соединитель двух разных объектов
есть ПК и флешка, картридер, юсб сдром
у всех возможность соеденяться через USB с ПК
interface Iusb {
void connect();
}

class flash implements Iusb {
void connect() {
System.out.println("connect flash");
}
}

class cardreader implements Iusb {
void connect() {
System.out.println("connect cardreader");
}
}

class usbcd implements Iusb {
void connect() {
System.out.println("connect usbcd");
}
}

class PK (Iusb usb) {
usb.connect();
}

PK(new cardreader); //connect cardreader

Правильно понял?

Ну вот, а теперь вспомни историю о том, как сначала был USB 1.0, потом 2.0, потом 3.0, каждый раз получается твой класс PK менял реализацию, потому что внутренности порта менялись, а все старые устройства на новых портах как работали так и работают, и новые устройства на старых портах тоже работают. Почему? Потому что интерфейс остался общий.
А теперь вспомни историю смены портов на макбуке или айфонах, и во что это все выливалось в итоге.

Не совсем соединитель, скорее описание того общего, что должно быть у объекта, если он утверждает, что имплементирует интерфейс. У каждого USB-девайса есть USB-порт, соответствующий спецификации USB. У него могут быть и другие порты со своими спецификациями, и что-то без спецификаций, но если USB-порт есть, мы можем обращаться с конкретным девайсом так же как с любым другим: подключить его к другому USB-порту, потому что у него есть порт USB, соответствующий спецификации USB.

Интересует правильно ли я понял
1. Интерфейс придает понимания архитектуры, структуры описываемых объектов и логики программы; гибкости за счет внесения дополнительной абстракции?

2. По правилам хорошего тона в программировании, даже если я ну на 100% уверен, что рыба не будет бегать, то все равно нужно писать class fish (Imove move) ?

3. Использовать интерфейс — это как абстрагировать не свойства, а возможности.
Для свойств — абстрактные классы. Животное: собака, рыба, орел. Дает возможность использовать один код несколько раз. Например присвоение животному имени.
Для возможностей — интерфейсы. Перемещаться: бегать, плыть, летать. Дать объекту возможность, что то делать, но без четкого указания, что именно и как. дать абстрактную возможность, чтобы потом иметь возможность ее всегда подменить на реальное действие.

Дайте ответы в формате
1. да
2. нет. объяснение почему

спасибо!

когда каждый пишет свои мысли, то я еще больше путаюсь

1. Як на мене речення не має сенсу (точніше, можливі надто широкі тлумачення), але тематика вірна.
2. Ні. Не робіть те, що 100% не треба.
3. Ні. Якийсь SetParameterX/GetParameterX — може бути в інтерфейсі для властивості. Інтерфейс (або, можливо, декілька інтерфейсів разом) дає все, що треба тому, хто використовує те, що ховається за інтерфейсом. Деталі реалізації (тобто, як зроблено функціонал, що виконують функції інтерфейсу) — сховано від користувача інтерфейсом, в цьому профіт.

Ще — бійтесь наслідування. Rule of thumb: composition > inheritance. Ще усі ці риби птиці з літанням та плаванням — надто заплутують. В реальності це реалізується за допомогою Entity Component System, а не наслідування.

1...3 Нет.
Интерфейс определяет то, что обїект, с которым выполняются какие-то действия, _реализует_ требуемый набор операций и свойств.
Если рыба не ходит, значит будет интерфейс Ходящие и Плавающие.
Архитектуру реализуют наборы методов, а не типы данніх. Тип данных немного дает в понимании архитектуры.
Бывают пустые интерфейсы-маркеры, чтобі можно было понять: єто _тот_ обьект или _не тот_.

Неправильный термин «данные». Правильно — ресурсы. Читать: тип ресурса.

ресурсы — это данные

Єто не resources, єто именно ресурсы — assets.

это и есть данные :)
ресурсы — это соль, керосин и спички

В соседней ветке человек — ресурс )) Он ест (интерфейс), работает (интерфейс), имеет имя (интерфейс).
Компания его использует, он спит дома — архитектура.
Ну, и такое всякое.

ест

ио

работает

ио

имеет имя

ну проперти жеж

Компания его использует

ио

ну проперти жеж

В C# интерфейс может декларировать методы, свойства, ивенты, индексы...

жуть какая. а в плюсах интерфесов нет. есть пюре из абстрактных классов :)

свойства, ивенты, индексы.

и вот этого вот всего трэша нет

и вот этого вот всего трэша нет

свойства это методы, ивенты это обертка над массивом ссылок на методы, индексы есть...

Єто все синтаксический сахар. Свойство в шарпе — єто два метода гетер и сетер, выглядящие как поле обїекта. Ивент — грубо говоря, ссылка на колбек. Внутри все-равно — классика.

Reflection в 10 разів повільнішій

Майкрософт

МС не шарит в интерфейсах. Посмотри на венду 10, говно же лютое, какие интерфейсы, какие рекомендации :)

У мене вінда 10. Все ок

Рабочие компы с 10. С одной партии закупки. С одинаковой виндой. Стоят два компа — один мой, один не мой. Мне удобно язык раскладки привязать на Ctrl+Alt+[2-4]. Соседний комп запоминает норм. Мой — теряет после перезагрузки. Еще раз, чтобы прочувствовать. Винда не может запомнить стандартную комбинацию для переключения раскладки. И такого сотнями сплошь и рядом.

Медленная рефлексия только та что на строки завязана, чтение атрибутов быстрая операция, к тому же кешируется если надо

І це поганий вибір.

Нет. Маркерные интерфейсы норм тема.

а конкретніше атрибут створити

Атрибут не прикрутишь когда нужна типизация по маркеру, азаза :)

1. Да
2+3.
interface Alive {
boolean isAlive();
void kill();
}
enum Environment {GROUND, WATER, AIR}
interface Movable {
boolean canMoveIn(Environment e);
}
interface Swimmable extends Movable {}
interface Walkable extends Movable {}
interface AliveTemperatureDependent extends Alive {
boolean canLiveAgainAfterFreezing();
doulbe temeratureLifeTreshold();
}

class Fish implements AliveTemperatureDependent, Swimmable {
// you have no idea how this class would work but you already have understanding how an object of this class should behave.
}

еще не написав ни строчки реального кода ты уже имеешь модель. Но это лишь примитивный и потенциально спорный пример. Иногда все наоборот — имея уже реальные классы, ты видишь необходимость их объединения одним поведением.

Немного о рыбах, в способности ходить которых я сомневался polymus.ru/...​ei/ask_a_scientist/16772

Інтерфейси потрібні для організації модульності. Вони дозволяють зробити з модуля black box, де ти можеш не знати деталі реалізації, тільки що саме він робить. Проблемно пам’ятати, як працює увесь додаток, менш проблемно пам’ятати, що робить конкретний модуль. Що робить модуль — описується завдяки інтерфейсу. Тому, хто використовує модуль, по коду не треба знати нічого, крім інтерфейсу. Крім суто когнітивних переваг — модулі структурують код і його стає легше змінювати. При зміні ідентифікуються модулі/інтерфейси, які треба змінити і таким чином задача зміни легше локалізується та розбивається на підзадачи. На невеликих проектах, де ти знаєш усе — модулі практично не потрібні.

Спасибо всем кто откликнулся.
Из Ваших ответов понял по теме больше, чем перечитав за несколько дней статей умных.

Правильно ли я понимаю.
Использовать интерфейс — это как абстрагировать не свойства, а возможности.
Для свойств — абстрактные классы. Животное: собака, рыба, орел. Дает возможность использовать один код несколько раз. Например присвоение животному имени.
Для возможностей — интерфейсы. Перемещаться: бегать, плыть, летать. Дать объекту возможность, что то делать, но без четкого указания, что именно и как.

Например пишем игру про собаку.

Interface Imove {
void StartMoving();
}

class run implemetns Imove {
void StartMoving() {
}
}

class toswim implements Imove {
void StartMoving() {
}
}

Если первоначально мы задумали, что собака будет только бегать, то можно было бы не писать интерфейс и имплементировать его. Сделать так.

class dog (run move)
{
move.StartMoving();
}

Но когда, изначально или потом заказчик игры попросит сделать возможность и плыть для собаки, то пришлось бы переписать класс dog так:
class dog (Imove move)
{
move.StartMoving();
}
создать class toswim implements Imove

А если сразу бы интерфейс использовали, то только добавить класс class toswim implements Imove

В этом моменте выражается помощь интерфейсов в придании гибкости в код?

Правильно ли я понимаю, что по правилам хорошего тона в программировании, даже если я ну на 100% уверен, что рыба не будет бегать, то все равно нужно писать class fish (Imove move) ?

Я бы рекомендовал посмотреть на паттерны Стратегия и Абстрактная Фабрика. Думаю будет понятнее. Или еще больше запутаешься. В твоем случае оплата через разные системы — это стратегии. Создавать их будет фабрика в зависимости от выбранного параметра. Это позволит проще тестировать реализацю клиента и добавлять новые методы оплаты не меняя клиент.

Тоже имел такую проблему, даже уже гребя поломанным веслом на галере, много качественной практики поможет, то что ты показал это маленькие кирпичики большого здания которое ты наверно никогда не строил и не знаешь зачем нужен архитектор если просто-ложишь-кирпичи-и-вот-тебе-стена-уже. Гуд лак!

В твоем примере интерфейс позволяет легко добавить новую платежную сиситему или сделать ее тестирование через обьекты которые переводят деньги из тестовых аккаунтов на тестовые аккаунты и тебе не нужно переделывать логику которая собственно дерегает метод pay() ибо ей плевать что там внутри — вебмани или пейпал, она должна дернуть метод pay а потом дождаться результата OK и отправить имейл с письмом что товар куплен и отправлается по указанному шипмент адресу.
Обьекты которые реализуют твой метод pay() инкапсулирую всю муторную хрень нужную конкретно для каждой платежной системы.

теоретический плюс использования интерфейса будет если писать примерно так

class Client {
        void pay_with(Topay payment)
        {
             payment.pay();
        }
}
на практике же интерфейсы используются когда это какая нибудь система для банка и тебе положенно реализовать какой нибудь модуль принимающии из вне интерфейсы реализованые индусами в далеком Бангалоре, но поскольку эта система настолько огромна что тестовый сетап подымается несколькими девопсами пару дней то для отладки ты используеш фейковые реализации этих интерфейсов написаные вчерашними студентами которых твоя галера наняла после курсов.

Например интерфейс IDispose, тебе плевать что внутри этого обьекта, сетевой конекшен или файл на локальном диске, тебе даже похрен на остальную логику там внутри, все что ты хочешь это метот Dispose, чтобы освободить unmanagement ресурс. Тебе даже похрен откуда он пришел это обьект и куда поедет дальше, просто у тебя есть момент времени где этот метод должен вызваться.

Есть еще IEnumerable это можеть быть массив с числами а может быть обьект который связан с таблицей в базе данных, но все что тебе от него нужно это чтобы он мог возвращать обьект IEnumerator и ты мог бы по нему пройтись в цикле for each, будет ли он в каждой итерации делать новый селект из базы данных или читать данные из файла или это будет данные из памяти от замоканного обьекта с тестовыми данными тебе плевать. Ты хочешь чтобы можно было юзать его в for each цикле.

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

1. Нет времени обьяснять, всегда(!) называй интерфейс с заглавной I => ITopay
2. Нагляднее всего преимущество интерфейсов для твоего примера покажет использование реализации Dependency Injection (читай в инете про Inversion of Control) когда ты будешь, например, в конструктор класса Client получать обьект класса реализующего интерфейс:

class Client (ITopay payment) {
.....
payment.pay();
}

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

всегда(!) называй интерфейс с заглавной I

нахуано сомбреро? Я звичайно розумію шо в дотнетчиків такі порядки, але в інших — зовсім не обов’язково.

а також ClientDTO, PaymentVO і тому подібне сміття з префіксами та постфіксами.

нахуано сомбреро?

Чтобы в коде сразу же понимать кто его носит

Яким чином?)

Ок, раз вам нравится по-другому — не буду настаивать. Но для меня лично довольно важную информацию при чтении кода несет понимание это класс или интерфейс.

Я думав це і так видно по
а) іконці в IDE
б) ключовому слову implements/interface

а) іконці в IDE

это не вещде есть, в вижуал студии,например, нет

б) ключовому слову implements/interface

то надо открывать файл

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

Постфиксы в твоем примере крайне редко встречал.

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

Потому что интерфейс это чистейшая абстракция, там нет логики, полей, конструкторов

Ты будешть удивлен, но в C# 8 предлагают добавить возможность реализовывать логику в интерфесах. А CLR это и так умеет.

Я видел это, надеюсь не введут, ибо это лютый бред.

Нет, не бред. В джаве дали дефолт методы в интерфейсе и это прекрасно. Можно внедрять классо-независимую поведенческую высокоуровневую логику.

Эту логику также хорошо можно разбивать на модули (если надо с иерархией) и внедрять через DI посредством интерфейсов. При это сохраняется single responsibility и разбивка по функционала по модулям.

было без дефолтных методов:

interface Shape {
    void setWidth(width);
    void setHeight(height);
    void redraw();
}

class Rectangle implements Shape { 
    ....
    // impementation-dependent
    void resize(int height, int width) {
        this.height = height;
        this.width = width;
        this.redraw();
    }
}

class Square implements Shape { 
    ....
    // impementation-dependent, duplicated
    void resize(int height, int width) {
        this.height = height;
        this.width = width;
        this.redraw();
    }
}

стало с дефолтными методами

interface Shape {
    void setWidth(width);
    void setHeight(height);
    void redraw();

    // became implementation-independent
    default void resize(
              int height, int width) {
        this.setHeight(height);
        this.setWidth(width);
        this.redraw();
    }
}

class Rectangle implements Shape { 
    ....
}

class Square implements Shape { 
    ....
}

суть басни — implementation-independent common логика вынесена на уровень абстракции. Без ДИ и инжекции, которая тут не при чем.

Почему нельзя вынести resize в базовый класс для фигур? И почему интерфейс содержит реализаци метода resize? как это мешает redraw и прочим методам?

Почему нельзя вынести resize в базовый класс для фигур?

Причин 3 (как минимум)
1) потому что мы сейчас говорим об интерфейсах
2) потому что перенесенный метод является абстракцией поведения, а не абстракцией структуры, которая представлена абстрактными классами.*
3) абстракции на интерфейсах всегда лучше таковой на абстрактных классах.

* походу все таки не зря на собесах травят вопросами про абстрактный класс и интерфейс.

И почему интерфейс содержит реализаци метода resize?

Потому что resize — их общее поведение, а не структура. И это поведение можно отвязать от структуры конкретной реализации, как первом примере, где ресайз завязан на филды реализаций, а не их методы.

как это мешает redraw и прочим методам?

А где я написал, что им чтото мешает? Я убрал дубликацию, сделав код максимально абстрактным, не зависящим ни от сторонних библиотек, ни от других абстракций.

Ты можешь хоть в класс AbstractShapeDrawerOnResize этот метод вынести (допустим, ты же хочешь ДИ), но это будет плохим решением, поскольку не логично, увеличит количество зависимостей и степень связности, уменьшает читабельность (2 файла вместо 1 смотреть)

Сорян но это все выглядит не убедительно, место resize в базовом классе а не в интерфейсе. Это общее поведение для фигур.

походу все таки не зря на собесах травят вопросами про абстрактный класс и интерфейс.
выглядит не убедительно

Увы, не могу помочь.

место resize в базовом классе а не в интерфейсе.

Нет. Вернее, ты можешь положить его куда угодно. Вопрос только в том, насколько много проблем твое решение породит в дальнейшем.

Это общее поведение для фигур.

Поведение должно определятья интерфейсом. Что и выяснили — ты путаешь структуру-класс (как работает), которая у всех разная может быть и поведение-интерфейс (как должно работать), которое у всех одинаковое.

Интерфейс не должен создавать структуру класса, у него одна задача — контракт\требование, класс должен быть resizable, clickable...для придания структуры и поведения классов есть наследование и абстрактные классы которые ограничивают и требуют посредством абстрактных методов, виртуальных методов и конструкторов своих наследников, таким образом ты придаешь форму наследникам и гворишь им как вести себя, ты выстраиваешь иерархию.

А интерфейсу вообще плевать на классы которые его реализуют, он ничего не хочет знать от них лишь чтобы они соглашались на его контракт\требования быть клакабельным или уметь менять размер

Ты путаешь структуру и поведение, одновременно отрицая мои тезисы и подтверждая их и не понимая этого.

для придания структуры и поведения классов есть наследование и абстрактные классы

Принципиально ошибочное понимание. Для структуры — а.классы, для поведения — интерфейсы. А ты спутал теплое с мягким в одну мухокотлету.

А интерфейсу вообще плевать на классы 

А где я сказал обратное?

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

Ты говоришь как человек, вчера узнавший об ООП, но еще не поняв, что в ООП можно утонуть, и что ООП можно готовить не только как Cat extends Pet extends Animal. Ты не обязан выстраивать единую форму и иерархию. Деревья иерархии интерфейсов и аклассов не обязательно должны вообще пересекаться. Сейчас из твоих слов создается впечатление, что ты думаешь, будто интерфейс это такой файлик документации, облегчающий просмотр публичных методов.

(туплю и не перечитал ветку с начала дискуссии)
del

выглядит не убедительно

Дай свой имейл, я вышлю тебе пример реального интерфейса, в котором всего 4 абстрактных геттера,12 дефолтных методов, 2 статических метода для работы с коллекциями объектов под этим интерфейсом и 1 статическое поле консьюмера для валидации. И у этого интерфейса 5 совершенно разных реализаций, которые представляют из себя совершенно разные вещи, но шарят общее поведение.

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

Поэтому я поведение\реализицию предопочитаю прятать через наследование и инкапсуляцию и предоставляю через интерфейс только способ с ним взаимодействовать.

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

в том что ты считаешь что интрефейс это и есть все поведение обьекта

Это не так. Где я такое написал?

в базовый класс для фигур?

И в целом, абстрактные классы нужно использовать крайне осторожно. Только если есть необходимость иметь общую структуру для наследников.

Структура — это в основном, поля, которые могут быть гораздо сложнее примитивных типов данных, как в моем примере, и конструкторы, которые задавают варианты инициализации структуры для наследников. Еще вариант — private/package final/protected final методы, которые только группируют манипуляции с общей структурой и доступны наследникам как часть структуры, а не пользователям как часть поведения.

Все остальное, особенно публичное, даже гет/сет, при возможности, следует выносить в интерфейсы. resize() в данном случае — это абстрактное поведение, которое опирается на абстрактную возможность задать размеры и абстрактную возможность перерисовать.

Крутая ветка, тоже посмотрел на некоторые вещи под другим углом.

Согласен до гет\сет :-) я как раз за то чтобы в интерфейсе был один метод resize, таким образом ты говоришь что эти обьекты могут менять свой размер, а то как они работают тебе должно быть пофиг, потому что таким образом ты их ограничиываешь но ты не ззнаешь их иерархию,(может это квадрат с 4 точка а может это будет вооще круг с центром и радиусом) для иерархии используется наследование а абстрактные классы, они сами знают как там в этой ирерахии жить и взаимодействовать.

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

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

хз нормально ли я обьясняю свою позицию :-)

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

В моем примере тебе как раз пофиг. Но ресайз определен на уровне абстракции поведения. Не совсем понятно, с чем ты споришь.

но ты не ззнаешь их иерархию

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

хз нормально ли я обьясняю свою позицию :-)

Ты по сути просто перефразируешь очень общие положения ООП о сокрытии, 42 и прочее, абсолютно не касаясь разницы акласс-вс-интерфейс и изначальной посылки — абстрактной логики в интерфейсах, которые в джаве реализуются дефолтными методами. А с 9ки еще и приватными дефолтными и приватными переменными.

Ну ок так ок, пишите логику в интерфейсах.

Если говорить о четырехугольниках, то seems legit. А если будем говорить не только о них?

Ну такая себе постановка дискуссии :) Я привел примитивный пример, на котором показал принципиально возможную целесообразность. Конечно, возможны и случаи, в которых это нецелесообразно или даже невозможно, если методы требуют разной имплементации. Я специально привел пример, где логика поведения идентична для разных классов, т.е. ее можно шарить из абстракции.

порочная майкрософтовская практика венгерской нотации. не рекомендую

что значит не рекомендуешь?) попробуй на шарпе попиши иначе, ее нужно испольщовать там где ей место, а не везде и так же со всем остальным

Я пишу на жаве и там такого нет. Интерфейсы обычно называют прилагательными — Suckable, Fuckable

в дотнете таких именных договоренностей нет, по факту в джаве вместо I- пишут -able

Сменил префикс на постфикс. Принцип тот же — название говорит что это такое перед тобой.

Это не является обязательным. Та же стандартная библиотека имеет много исключений . Мое имхо — все эти модификации имён не нужны. Во первых в ИДЕ наведешь мышку и видно что это. Во вторых не очень то и нужно знать, класс это или интерфейс для понимания логики кода, если он написан не через дупу

Ну это дело привычки больше, мне так привычно, если для других другое привычно то тоже IОК ну или OKable :-)

А что произойдет, если на C# убрать префикс I из интерфейса? Или _ (m_) из имени приватных полей? На сколько я помню, что все, что осталось от венгерской нотации.

Билл Гейтс наложит стройматериалов ? 😂

А что произойдет, если на C# убрать префикс I из интерфейса?

для компа ничего, а для людей, которые будут читать такой код лишние напряги

Или _ (m_) из имени приватных полей?

m_ с плюсистами пришло, в шарпе он никогда не был рекомендуемым, если убрать _ то потеряешь грань между переменными и полями класса, обычно это только во вред, особо отбитые пишут без подчеркивания, но обязательно с «this.» чтобы отличить

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

А-а, да, еще Async в асинхронный методах.

а для людей, которые будут читать такой код лишние напряги

Дело привычки, которые стоит менять время от времени чтобы не ржаветь.

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

Welcome to R#/Rider.

автоматическое di

зло само по себе, но тоже во многих случаях опирается на тип, а не на I.

Дело привычки, которые стоит менять время от времени чтобы не ржаветь.

одной нотации для одного языка вполне достаточно

Welcome to R#/Rider

ну вот r# как раз и перестанет это нормально обрабатывать, начнет вопросы задавать

одной нотации для одного языка вполне достаточно

var или явное указание типа в определении переменной?

ну вот r# как раз и перестанет это нормально обрабатывать, начнет вопросы задавать

Если продолжает так себя вести после изменения конвенций в конфиге, тогда welcome to Rider 🙂. Но вопросы он задает и при использовании префикса I.

var или явное указание типа в определении переменной?

общепринято писать вар, но староверы против

Угу. А еще они против удаления I из названий интервейсов, _ из приватных полей и Async из имен асинхронных методов 😉.

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

изменение на вар оправданное, тип сущности ничего не дает

Как на счет

var value = service.GetValue();
return JsonConvert.Serialize(value);
и
var value = await service.GetValue();
return JsonConvert.Serialize(value);
?
service.GetValue Один и тот же в обоих случаях.

я бы вообще тавро ставил тем кто асинхронность тулит везде, а потом пишет синхронный код, раньше асинхронные операции были крайне редкие и их выделяли отдельно, вот все что я могу сказать

Эмм? Любое обращение к бд или файловой системе, или внешнему сервису асинхронно по своей природе.

А в примере автор просто забыл заавейтить результат и компилятор ему не подсказл, потому что var зарезолвился в Task.

Эмм? Любое обращение к бд или файловой системе, или внешнему сервису асинхронно по своей природе.

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

А в примере автор просто забыл заавейтить результат и компилятор ему не подсказл, потому что var зарезолвился в Task.

туда можно притулить получение результата очень разными способами, я просто проигнорил, думая что речь идет об именовании

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

Любое обращение к бд или файловой системе, или внешнему сервису асинхронно по своей природе.

нет

А должно быть. Особенно на бэкенде.

если оно в отдельном треде то нафик не надо

Ладно, просто спрошу знаешь ли ты сколько памяти занимает поток и про context switching?

вау. ну ты валишь меня. откуда ж мне такое знать? тыбы еще про thread stack спросил бы
в свою очередь спрошу — ты в курсе, что асинхронный это не всегда мультипоточный?

тыбы еще про thread stack спросил

Хотел, но решил keep it simple.

ты в курсе, что асинхронный это не всегда мультипоточный

В курсе.
Но тогда у меня когнитивный диссонанс. Как ты, понимая как оно устроено на низком уровне, можешь утверждать что

если оно в отдельном треде то нафик не надо

?

давай з азов начнем — зачем на бекенде нужна асинхронность?

Посмотрел на твой опыт разработки бэкенда. Проехали.

технично слился. молодец.

Я старался, спасибо. Переживал, что обидел. Я рад, что ты не обиделся. Вот это видео в свое время сильно повлияло на мое понимание того, что происходит channel9.msdn.com/...​Microsoft-SWIT-2014/swit5.

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

завтра уже. печатать надо много, с телефона не удобно

ладно, понеслась
будет сумбурно, потому, что много писать не люблю, а тема явно не для одного сообщения

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

нам нужно организовать работу тс сущностями так, чтобы запрос к базе не блокировал работу сети и тп

что же нам предлагают гении програмистической мысли на сегодняшний момент?
в рамках ОС мы можем создавать:
1. процессы
2. треды
3. асинхронные таски

Пройдемся по каждому (плюсы и минусы)

Процессы:
плюсы: поддержка на уровне ОС (вытесняющий мультитаск, шедулинг), независимое адресное пространство, умерший процесс никак не отразится на родительском процессе, возможность работать на разных ядрах
минусы: независимое адресное пространство (тяжело контроллировать, что там внутри), большие накладные расходы на создание и работу

Треды:
плюсы: поддержка на уровне ОС (вытесняющий мультитаск, шедулинг), адресное пространство такое же как и у родителя (кроме стека), относительно низкие затраты на создание (по сравнению с процессами), возможность работать на разных ядрах
минусы: умер тред — умерла аппа, создание треда и переключение контекста небесплатно

Асинхронные таски
Тут каждый городит кто во что горазд. важно понимать, что асинхронные задачи, что в сишарпе, что в жабоскрипте работают в основном треде. как это делается? Создается некая очередь сообщений и цикл, который обрабатывает эту очередь. допустим нам нужно запустить некий запрос и продолжать заниматься своими делами, пока запрос гуляет по сети. мы кладем в очередь сообщений сообщение с запросом, запрос запускает некую цепочку действий в ОС, которая исполняет запрос. если запрос неблокирующий, управление возвращается в приложение и приложение продолжает работать, установив обработчик завершения запроса. таким образом создается иллюзия многозадачности. проблемы начинаются, если запрос блокирующий или очень тяжеловесный. дла гуи приложения это будет выгладеть как неотзывчивый интерфейс. не забываем, что все выполняется в одном треде. это так называемый кооперативный мультитаск. так работала винда 3.1
плюсы асинхронных таском — нет накладных расходов на создание треда и тп
минусы — описаны выше. программисту надо заботится, чтобы запрос не заблокировал очередь, никакого шедулинга

Для гуи приложений правило номер раз — никогда не работать с диском, сетью, базами данных, не рассчитывать ничего сложнее 2+2 в основном (ГУИ) треде. даже через асинк таски
все эти задачи должны быть вынесены в отдельные треды или процессы

как то так
извините, если чтото пропустил или гдето безбожно туплю

Пользуясь случаем запощу толковый мануал по хорошим/плохим патернам использования асинхронных тасок в дот нете. Они и строятся преимущественно вокруг идеи не блокирования потока. Всем сишарпнутым читать обязательно

github.com/...​b/master/AsyncGuidance.md

Тут каждый городит кто во что горазд. важно понимать, что асинхронные задачи, что в сишарпе, что в жабоскрипте работают в основном треде

в C# работают через очередь тасков, есть глобальная и есть на каждый тред из пула, проблема может быть в слишком частом переключении между тредами или в оооочень тяжелых тасках на тред которые ведут к тому что создается очень много новых тредов которые долбят долго и нудно свою задачу. В целом же тут нужен баланс — между переключениями и загрузкой треда. Все это сводится к тому чтобы программист понимал что он нагружает и как и сам решал что ему действительно нужно — создать руками один тред и там постоянно что-то долбить или сваливать все через очередь, так же количество тредов в пуле зависит от машины...Тут нет одно четкого ответа, так же как и вопроса :-)

в C# работают через очередь тасков, есть глобальная и есть на каждый тред из пула

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

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

если оно в отдельном треде то нафик не надо

звучит как минимум странно.

На сервер приходит множество запросов. И эффективнее использовать столько потоков, сколько есть ядер, чтобы минимизировать переключения контекста. А блокорование потока принуждает создавать новые. Что ведет к увеличению переключений контекста.

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

моя фраза относилась к тому, что если асинк таски выполняются в пределах одного треда, и работа с БД вынесена в отдельный тред, то работать с асинками в пределах одного треда бессмысленно

Глупый кейс какой-то.

если запросов очень много, то да, надо выделять пул тредов и делать шедулинг с помощью пула тредов

В .NET это все из-коробки.

если асинк таски в сишарпе дергают треды из пула, то претензии к стоимости треда бесмысленны.

Это только говорит о том, что ты не достаточно хорошо понимаешь как оно устроено внутри. Но ты не на .NET пишешь и понятно что тебе в это углубляться не за чем.
Я понимаю, что цель разобраться не стоит, поэтому, думаю, дискуссию можно сворачивать. А если интересно понять как оно, в частности в .NET, — видео, которое я сбросил выше очень норм.

Глупый кейс какой-то.

потому, что это не твой кейс?

В .NET это все из-коробки.

меня мало волнует .нет: за пределами .нет тоже есть жизнь
я тебе рассказываю, как оно устроено на системном уровнеЮ а ты аппелируешь уровнем приложения

Это только говорит о том, что ты не достаточно хорошо понимаешь как оно устроено внутри.

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

дискуссию можно сворачивать

таки да

если интересно понять как оно в частности в .NET

таки нет :)

потому, что это не твой кейс?

Да я говорил о том, как это обычно делают на C#.

я тебе рассказываю, как оно устроено на системном уровне

Спасибо, я понимаю как оно устроено на системном уровне.

это говорит только о том, что ты недостаточно понимаещшь, как оно устроено ниже дотнета.

Lol, ok.

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

Ох, континюэйшены асинков шедулятся на тред пул. Это не взаимоисключающие вещи, это про одно и то же. Ладно, я вижу интерес потроллить, а не разобраться, поэтому давай закругляться.

я вижу интерес потроллить, а не разобраться,

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

В таком случае,

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

Их лучше использовать потому что их продолжения выполняются на пуле потоков, а

с другой стороны признаешь, что все таки используется тредпул

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

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

Ты подходил к дискуссии с целью доказать собеседнику, что он не шарит или несет чушь. Может, лучше из этого извлечь урок?

т.е. по твоему, работа с тредпулом не приводит к переключению контекста ядра?

Нет, я говорил о том, что если количество потоков в пуле развняется количеству ядер, то переключение контекста будет минимальным. А если блокировать потоки пула, он будет создавать больше потоков, что приведет у переключениям контекста.

если количество потоков в пуле развняется количеству ядер, то переключение контекста будет минимальным

с этим кагбе никто не спорит
просто в каждом случае нужно считать что будет дороже: перключение контекста или заблокированный тред

Вот в UI как раз пофиг на заблокированный тред. А на сервере разница очень существенна.

Вот в UI как раз пофиг на заблокированный тред.

юзеру не пофиг. он начинает нервничать и хочет разбить девайс об стену

Ну, мы же про заблокированный бекграунд тред в контексте дискуссии.

если оно в отдельном треде то нафик не надо

Я понял, тебе трудно восстанавливать контекст после переключения.

ааа, таки не удержался и перешел на личности?

Вот блин, непроизвольно получилось. Сорян.

Так в том то и дело что бесит дерганный интерфейс который лочится, но если лочится процес не UI-ный то это пофигу, ты нажал на кнопку, она поменяла фон и включился прогресс бар, но остальные кнопки работают. Кончено можно затыкать приложение до смерти:-) Но UI то овтечает, а значит уже не так бесит.
Меня так на айфоне бесит google music, вот там видно что нагружает проц так, что даже тред с UI дергается и корчится и собственно хрен пойми, то ли это проц не успеает UI тред отработать, то ли UI тред лочится.

меня мало волнует .нет: за пределами .нет тоже есть жизнь
я тебе рассказываю, как оно устроено на системном уровнеЮ а ты аппелируешь уровнем приложения

А как оно устроено на уровне ОСи тоесть в IOCP, kqueue, epoll например? Разве там не все на ивентах? о каком блокировании потока на уровне системы речь?

я бы вообще тавро ставил тем кто асинхронность тулит везде

Асинхронность хороша там, где она нужна. А нужна она бывает не сказать чтобы редко.

почему-то у меня редко встречаются задачи, в которых порядок действий неважен

А у меня весьма часто. А сейчас мы пишем сервис, в котором вообще почти вся логика на асинхронности, ивентах, передаче иммутабл состояний, и рид-райт локах.

у меня закралось подозрение, что ты не различаешь асинхронность и многопоточность, можешь его развеять? потому что по описанию я не могу представить ничего кроме кластера ферм для фарминга крипты, но зачем в нем локи

у меня закралось подозрение, что ты не различаешь асинхронность и многопоточность, можешь его развеять?

Поначалу даже не знал что на это ответить. Ты хочешь чтобы я доказывал, что я не верблюд. Сорян, но нет.
Лучше сам проверься, держи
stackoverflow.com/...​ing-is-there-a-difference
а заодно подумай над принципиальной корректностью вопроса.

Поначалу даже не знал что на это ответить. Ты хочешь чтобы я доказывал, что я не верблюд. Сорян, но нет. 

на самом деле я ждал «да, различаю» или «нет, не различаю»

Лучше сам проверься, держи
stackoverflow.com/...​ing-is-there-a-difference

у меня и так все хорошо, чего мне проверяться?

а заодно подумай над принципиальной корректностью вопроса.

смысловая нагрузка вполне корректная, словесная интерпритация — это мой максимум мягкости

смысловая нагрузка вполне корректная,

Увы, нет. Жаль, что ты не понимаешь. Почитал бы линк что я кинул, может натолкнуло бы на какие-то мысли.

специально открыл, каждый второй отвечает что асинхронность и многопоточность это разное, на какие это меня мысли должно натолкнуть?

на какие это меня мысли должно натолкнуть?

На то, что различие асинхронность/многопоточность на самом деле лежит не более чем в абстрактной, спорной и зыбкой терминологии и что в зависимости от контекста обсуждаемых технологий этот вопрос может иметь 0 смысла.

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

у тебя неправильное понимание

кулстори

синхронный многопоточный,

Пізвзреготнув. Між синхронним багато та однопотоковим кодом різниці нуль.

асинхронный однопоточный

Один потік — вже точка синхронізації.

Між синхронним багато та однопотоковим кодом різниці нуль.

Здрастье! То ли дело когда у тебя один грузичик, то ли дело когда два и больше грузчика.

Один потік — вже точка синхронізації.

это ты вообще о чем?

Здрастье! То ли дело когда у тебя один грузичик, то ли дело когда два и больше грузчика.

Привіт. Їм обом треба носити одну коробку через одні двері. Вперед!

это ты вообще о чем?

Про виконання твого коду. Як на одному ядрі виконуються багато програм та потоків в псевдопаралельному режимі?

Так не заставляй их носить одну коробку через одни двери, пусть каждый носит свое. Синхронизация потокв далеко не всегда проблема,в моем опыте, в основном задачи отлично расспаралелливались.

А насчет ядер я уже писал- асинхронный код и то как шарится проц между процессами это абсолютно разные вещи.

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

Це багатопотоковий асинхронний код.

Синхронизация потокв далеко не всегда проблема,в моем опыте, в основном задачи отлично расспаралелливались.

Синхронізація потоків в однопотоковому процесі? Підвзреготнув ще раз.

А насчет ядер я уже писал- асинхронный код и то как шарится проц между процессами это абсолютно разные вещи.

Чому це? Якщо твоя програма буде вимагати заблокованого ресурсу, то різниця між «синхронний код» та «асинхронний код» буде нульовою на момент виконання.

Чувак, ты упоротый?На всякий случай, это был риторический вопрос.

Ти просто розглядаєш кулеподібний код в вакуумі. Але опустися на рівень CPU та побач, в решті решт, що всі оці ґатунки багатопотоковості/асинхронності не більш ніж красива гра слів. Але упоротий, звісно ж, я. Ага.

Але опустися на рівень CPU та побач

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

А сенс обговорювати асинхронність та багатопотоковість, якщо на нижньому рівні все виглядає інакше? Навіть при переході на рівень OS. А ще є особливості реалізації. Ти будеш думати, що в тебе асинхронність, а реалізована вона може через багатопотоковість.

Ну и планировщик сейчас сильно навороченный и с кучей функциональности, которой большинство не пользуется.

кому надо — те пользуются. остальные живут в манямирках виртуальных машин

Т.е. проц один, но могли выполняться параллельно много потоков выполнения.

Не паралельно, а послідовно з гарантованим або таким, що плаває, часом виконання.

Это можно сказать виртуальные потоки.

Так отож...

Таки параллельно уже давно. В простейшем случае юзается разделение времени с приоритетами.

Якщо є розділення часу, то це вже послідовно. В системі немає потоків, кількість яких менша або дорівнює кількості ядер. Тому реальна паралельність майже не спостерігається. Може статися така халепа, що ваші два потоки будуть виконуваться на одному ядрі. По черзі, через певний квант часу.

Давай, пояснюй свою позицію. Чому псевдопаралельність ти називаєш паралельністю.
Назвав людей школотою, полізай на трибуну. ;)

Потому что разберись сначала в понятиях параллельность и псевдопараллельность.

Паралельність доволі таки вільний переклад терміна «simultaneous» (occurring, operating, or done at the same time.)
Так ось, водночас процесор може виконувати лише певну кількість потоків. Але немає жодної гарантії, що програма, яку було написано з використанням багатопотоковості буде використовувати більше ніж одне ядро/потік процесору. А ще немає гарантії, що ці потоки будуть виконуватися водночас, а не час від часу один потік на одному ядрі.

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

Правильно. Саме він не гарантує взагалі нічого. Навіть, що ядра будуть використовуватися. Тобто багатопотоковість на рівні програми може бути перетворена планувальником на послідовне виконання коду. А ще він може упоротися енергозберігайками та вимкнути всі ядра окрім одного.

Но у тебя есть вариант. Снеси ось и попробуй сам напрямую с процессором общаться, особенно современным. Хотя бы включи его и заставь хоть 2 числа сложить.

Що це мусить довести? Пан не знає про можливості сучасних біосів?

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

Есть объект А, который выполняет операцию с немалым объемом данных каждые Х секунд. Каждая работа может длиться рандомное количество времени, т.к. объем обрабатываемых данных не определен, и рандомно прыгает в широком диапазоне, от единиц до десятков тысяч. Запуск работы все равно происходит каждые Х секунд, т.е. каждый запуск происходит вне зависимости от того, закончена ли работа в предыдущем запуске. Этот объект содержит большое количество опций, которые непосредственно влияют на суть выполняемой им работы, и которые можно менять в любой момент времени по внешнему запросу, и которые сохраняются в бд. Также, по внешнему запросу можно получить те или иные опции объекта. Помимо этого, объект ведет некоторую статистику как по каждой из выполняемых работ, так и в целом. И эту статистику тоже можно получить по внешнему запросу. Помимо этого, этот объект содержится в контейнере наряду с другими подобными объектами. В любом момент контейнер может загрузить и поставить в строй новый объект, или остановить работающий. И контейнер также читает опции объекта по внешним запросам к самому контейнеру. Итого у тебя есть целая орда читающих операций и чуть поменьшее количество мутирующих операций, часть из которых порождает сам объект, а часть приходит извне. Тебе понятно, зачем здесь нужны рид-райт локи?

Есть объект А...

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

Тебе понятно, зачем здесь нужны рид-райт локи?

у них одно применение... синхронизировать многопоточный код...

Мда. Дальше не вижу смысла о чем либо на эту тему говорить.

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

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

опа! :) ответ на этот вопрос принят dou.ua/...​ign=reply-comment#1526525

достаточно одного потока чтобы писать асинхронный код

достаточно одного потока чтобы писать асинхронный код

Напиши мне асинхронный код на джаве, используя 1 поток.

Напиши мне асинхронный код на джаве, используя 1 поток.

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

Та просто какой-то message pump реализовать, где каждый item — это какое-то действие. По типу как в JS или UI thread.

пример, пожалуйста. На джаве, асинхронность с 1 потоком :)

Напиши мне асинхронный код на джаве, используя 1 поток.

public static void main(String[] args) {
int i = 0;
int i2 = 0;
while (i2 < 100){
if(i < i2) {
i = process1(i);
} else {
i2 = process2(i2);
}
}
System.out.println(String.format("i=%d, i2=%d", i, i2));
}

private static int process1(int i){
return i + 2;
}
private static int process2(int i){
return ++i;
}

А что есть в Вашем понимании асинхронность в 1 потоке? Как по мне — поочередное выполнение заданий, данный пример показывает, что передавая результат предыдущего выполнения, 2 независимых исполнителя делают работу с разной скоростью, и в данном случаи один ждет второго, когда тот отстает.
Пример при желании расширяется до размеров windows 98, работающей на одном процессоре.

А что есть в Вашем понимании асинхронность в 1 потоке?

Омг.

поочередное
асинхронность

Серьезно?

2 независимых исполнителя 

И в чем они независимы? Весь этот код работает строго синхронно.

один ждет второго
асинхронность

...

Серьезно?

Как же, по Вашему, работают одно ядерные процессоры?

А какая мне разница, как работают процессоры? Я что, на асме пишу? Я реально в ахуе от цикла который преподносится как асинхронность. Такое чувство что попал в филиал Кафки на доу.

а я ждал ответ что происходит мейоз и разделившееся ядро на два может держать два потока и только тогда появляется асинхронность :)

в ахуе от цикла который преподносится как асинхронность

интересно, для кого я сегодня простыню текста сутра писал в этой теме?

Не читал.
Прочитал.
Это несколько мимо. Ты опустился на уровень процессов ОС, который меня в контексте данной ветки не интересует от слова вообще. Выполнение кода в джаве синхронное. Любое асинхронное действие — это тред. Неважно, откуда он взялся. Действия, выполняемые в 1 треде строго синхронны. Если на уровне джава кода ты хочешь создать чтолибо асинхронное, ты используешь отдельный от основного тред. Другого способа нет. И на данном уровне мне все равно, как это будет работать на уровне ОС/процессора/драйверов/сети/ватэва. Если ктото пишет кровавый ентерпрайз на джаве, и при этом называет цикл вайл с и++ и саут.принтлн асинхронным кодом, ссылаясь на работу процессора, то блин, без комментариев.

Ты опустился на уровень процессов ОС,

я оттуда и не поднимался

Выполнение кода в джаве синхронное

нас рать на джаву и все виртуальные машины вместе взятые

Любое асинхронное действие — это тред

ты забываешь про евенты (прерывания), т.е. про железо
вспомни, как работали резиденты в дос

называет цикл вайл с и++ и саут.принтлн асинхронным кодом

это симуляция асинхронности, конечно. если ты внимательно читал мой пост, я именно об этом и писал

я оттуда и не поднимался

И нахиба мне тогда читать

ты внимательно читал мой пост

про низкоуровневую срань и такты процессора, если мне оно сто лет не упало и мы находимся в разных мирах?

нас рать на джаву и все виртуальные машины вместе взятые

Ровно как и мне космически насрать на кресты, контекст свич и низкоуровневые танцы с процессором :)

если мне оно сто лет не упало

тогда зачем спорить о том, как оно работает?

тогда зачем спорить о том, как оно работает?

А где я спорил о какойто низкоуровневой фигне? Вернее, где тебе показалось, что я спорил о низкоуровневой фигне?

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

Твой цикл может успеть выполнится за один такт, а может и за несколько, но в рамках JVM или .NET это обычный синхронный однопоточный код :-)

Но вообще это немного другая парафия. Винда сама останавливает выполнение процесса, безо всяких async\awаit указаний из кода.

В других осях все может быть немножко иначе и это обычно головная боль всяких приплюснутых системных программистов.

думаешь стоило раздувать его до многих экранов чтобы явно было видно тот же подход что в первых версиях виндовса был?

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

Да оно давно так в .NET — есть спецальный поток для GUI, а остальные вещи ты бросаешь процесситься в другой поток, через тред пулов, поэтому GUI не торомозит.

Но ты конечно можешь херачить логику прям в обработчике событий своей вин формы и тогда это все будет в потоке который для GUI, которы не только обрабатывать клики твоей формы но и ждет ответа от sql :-), ессесено там будут фризы.
И это не иллюзия.

А если ты про процессы которые шарят процессороное время, то это не то.
Ядро выполняет код только одного процесса(HyperThreading от Intel лишь кэширует, кажется, контекст треда и за счет этого не происходит «долгого» переключения контекста), а значит и GUI и все остальное в этом процессе, не работает, пока он в очереди. GUI будет не респонсив. Но обычно это не заметно :-) Но код все равно синхронный.

То как шарится процессорное время и асинхронность кода, это абсолютно разные вещи. Программируя на .NET\Java можешь вообще забудь про это процессорное время, если ты думаешь про асинхронность\многопточность:-)))
Все что ты можешь это указать — приоритет твоего треда — от среднего до ниже среднего, не помню уже как точно эти имена.

Вообще лучше сядь почитай статьи или Рихтера, собери какое нибудь простенькое приложение и поиграйся с этими штуками, тогда понимание прийдет само.

Собственно я уже и сам подзабыл многое, так, по памяти пишу.

Твой цикл может успеть выполнится за один такт, а может и за несколько, но в рамках JVM или .NET это обычный синхронный однопоточный код :-)

Это то, что я пытался сказать весь вечер, но видимо, плохо пытался.

System.out.println("async event 1");
System.out.println("async event 2");
int i = 3;
while (true) {
    System.out.println("async event " + i);
    i++;
}
System.out.println("truly asynchronous programming in Java, fuck yeah!!");

Pfff, stupid spring developers that created @Async, they did it wrong!

просто каноничный пример гуманитария-бармена, который поперся в айти из-за денег, абсолютный ноль технического образования

Это ты мне или автору цикла-с-асинхронностью?

Ах ну да. «Асинхронный» цикл в одном потоке в синхронной с рождения джаве. Вечер «технарей» на доу, прям праздник :)

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

ты не знаешь что значит синхронный и асинхронный

Увы, но ты даже гугл не можешь открыть, чтобы самому это прочитать и понять, что двигаешь чушь. Ссылку на вики уже привел, видимо, не помогает.

и есть та самая асинхронность

Я уже понял, что у гугла, вики и соф одна асинхронность, а у тебя другая :) увы, бессилен.

А вообще, если копнуть в исходники то видно что аснихронный код может выполнится снихронно без всей куйни :-)

он и так моим словам не верит, если я бы такое еще написал, то и так хрупкому диалогу пришла бы финита ля комедия, у него ж асинхронность это два потока, как они одним станут?)

Я там внизу цитату с вики привел, понимаю, что слишком сложно, но почитай.

не надо мерить всех по себе, мне совсем не сложно

Вики:

In computer programming, asynchronous events are those occurring independently of the main program flow. Asynchronous actions are actions executed in a non-blocking scheme, allowing the main program flow to continue processing.

Покажи, где в твоем цикле происходят events are those occurring independently of the main program flow. И где main program flow to continue processing, оставив какое-то выполнение чего-либо асинхронным?

Я не хочу продолжать разговор, это бесполезно. Считайте, что я слился.

Да я хз как на джава асинхронное IO реализуется. Вот можешь почитать про C# blog.stephencleary.com/...​1/there-is-no-thread.html. Что-то похожее долно быть и в Java (я не про async/await, а про взаимодейтвие с ОС и драйверами).

Да я хз как на джава асинхронное IO реализуется.

В джаве нет нативной асинхронности на уровне языка.

Что-то похожее долно быть и в Java (я не про async/await, а про взаимодейтвие с ОС и драйверами).

Да. мне кажется, что коллеги сверху, которые заливали про процессоры, так до конца и не поняли, о чем я пытался им сказать. Джава не взаимодействует с драйверами. Вернее, виртуальная машина взаимодействует, с ос конечно. Но на уровне джавы как приложения, которое пишет разработчик, нет никакой асинхронности процессоров, ОС, тактов и прочего.

async/await в джаве тоже нету, вместо этого есть пулы потоков и встроенный пул, который можно использовать, а также классы, предназначенный для работы с асинхронностью. Типа того самого Future, о котором ты упомянул.

И всякий RxJava, Vertex, асинхронные сервера и прочее — все это на пулах потоков.

Видимо, я неправильно выразился, неблокирующее IO в Java есть?

неблокирующее IO в Java

Есть. Это часть Java NIO. Ни разу не пользовался, не было нужды.

И да, асинхронность действий на уровне приложения != неблокирующее IO.

Да, вот тоже почитал немного про NIO. Но там все сильно по-другому. Но с неблокирующим IO можо прийти к асинхронности. Как в NodeJS, например. Только там это из-коробки. И в C#. Но мне вообще пофигу сколько потоков исользуется для реализации асинхронной операции или поведения, если они не блокируются.

Но с неблокирующим IO можо прийти к асинхронности.

Возможно. Но понятие «асинхронность» на уровне приложения гораздо шире возможности использовать нонблокинг ио и узкого контекста про процессоры и ос, в котором застряли авторы гениальных асинхронных циклов и++ сверху.

Если говорить об асинхронности за рамками асинхронного IO, то это уже становится частью модели системы (асинхронное поведение). И тут уже интересно смотреть в сторону Actor Model.

то это уже становится частью модели системы (асинхронное поведение).

О чем я изначально и говорил. Асинхронное поведение компонентов/процессов и есть, собственно, асинхронность.

Ну, да. Я изначально говорил про асинхронное IO.

первый раз вижу такое сочетание букв

В C# асинхронный код совсем не значит, что порядок операций нарушается, наоборот.

В C# асинхронный код

по-моему это у тебя что-то новаторское :) есть асинхронность и ее суть в том что задачи не зависят друг от друга и соответственно порядок их выполнения не имеет значения

Мой пример был об асинхронном вводе/выводе с Task и async/await.

не очень понятно о чем ты говоришь

Мы же с этого примера начали говорить об асинхронности dou.ua/...​rums/topic/26512/#1525132.

чет это уже очень давно было, он формально асинхронный, по факту синхронный, профита нет вообще, зато есть накладные расходы

Кхм, тогда, наверное, тебе будет интересно почитать нашу дискуссию с Владом.

та я смотрел, вы каждый о своем, а видео я в живую слушал, Рихтер пересказал главу своей книги, которая на тот момент недавно вышла

Я тоже был на том выступлении. Ну, если оно не убедило, то я хз. Могу только предложить посмотреть на нагладные расходы async/await в .NET Core 2.1/2.1.

так как оно там было рассказано все норм, но используют же бездумно везде всегда

То, что кто-то где-то бездумно использовал, ведь, не повод не использовать там, где оно применимо. А это любое IO.

я вроде нигде и не говорил обратного

var вообще идиотская хрень. Жалею, что его ввели в джаву по просьбам хомячья.

Я, когда начал пользоваться, понял на сколько удобно. Но зашло не сразу. И таких подводных камней не много, если не единичный случай.

А-а, да, еще Async в асинхронный методах.

Это за или против? Лично я всегда ставлю async в имени метода, если где-то как-то он объявлен асинхронным, или предполагается что он внутри асинхронный.

Мой поинт в этой дискуссии, что часто нет однозначно правильного ответа. Это все личные предпочтения и договоренности команды. Я Async не пишу в конце метода, хотя MS так рекомендует. Потому что у меня большинство методов асинхронные по природе. И в .NET с этим проще, потому что благодаря async/await асинхронный код выглядит как синхронный. Это как если бы в JS во все методы возвращающие Promise добавляли Async.

Мне тоже не нравится традиция дотнетчиков с префиксом И. В джаве интерфейс просто называется как adjective.

Сменил префикс на постфикс. Принцип тот же — название говорит что это такое перед тобой.

в стандартной библиотеке куча исключений. например Map, List, Collection — интерфейсы

В этом есть своя красивая логика, не спорю :)

interface Payayble {public void pay(Double sum);}
class Tiolka extends Client implements Payayble{
    Topay payment;
    Fuckable rotik;
    Fuckable zhopa;
    ....
    public void pay(Double sum){
       try{ payment.pay();
       }catch(KonchilisBabkiException wtf){
          new Topay(){
             public void pay(){
                 say("Deneg net");
                 say("Davay naturoy");
                 rotik.fuck();
                 ....
             }
          }.pay();
       }
    }
}

Согласен. В реальном коде это в 1-2 строчки пишется (если вменяемый проект) или на 8 файлов если раздутый. Но тут нужно показать сам факт, ЗАЧЕМ пользуются интерфейсы: для деградации логики кода. Логика на инетрфейсах понятна в коде пока на неё смотришь, и не требует использовать память человека. Как только закрыл код — думать уже не надо.

В случае рефакторинга ничего искать не надо, можно править в одном месте, не ожидая что рухнут остальные. Можно покрывать тестами — для тестов интерфейсы вообще прелесть. И разумеется, интерфейс — это прекрасный возвращаемый объект из методов, особенно дальних, с малопонятной внутренней логикой (и нежеланием с нею разбираться). Ты видишь, что прилетает интерфейс, ты можешь посмотреть что он делает, и НИ СЛОВА лишнего кода не читать вообще. И опять же, когда возвращается интерфейс, а не класс, его очень легко тестить, большинство примитивных тестов вообще автоматом генерятся.

Если коротко, это синтетический сахар, основная роль такая. Или если будет угодно, умение из бочки говна доставать конфетку, да так чтоб лапки не запачкать.

Когото явно на уютном покусали.

Воо, годные назвы для интерфейсов! if (aids instanceof Incurable) throw new PatientDiedException();

Особо весело когда китайский код надо править. Вроде всё на инглише, даже комменты, и тут какая-то бл...[полигамная самка китайца] назвала переменную иероглифом. Который даже не отображается. И на которую [ну так совпало] припадает баг.

За несколько дней перечитал кучу статей. Там 100 раз о полезности интерфейсов.

Зрозумієш вже на практиці, коли попрацюєш з чужим кодом і треба буде половину переписати :)

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

с интерфейсами:
IPaymentSystem
{
Deposit(IDepositInfo);
Withdraw(IWithdrawInfo);
}
если добавятся/удалятся параметры, то реализации IDepositInfo и IWithdrawInfo изменятся, если добавятся платежные системы, то достаточно реализовать IPaymentSystem, если удалятся, то просто удалить реализацию, если изменится что-то в платежной системе, то изменения только в ней и т.д.

другими словами с интерфейсов ты не получаешь цепочку боли, все изменения будут изолированы этим самым интерфейсом, но это обязывает к грамотному проектированию или, скорее всего, эффект будет обратный
--------------------------------------------------
если объяснение не зашло, то посмотри на linq, они применяются к любой коллекции, ты можешь не обращать внимание что там конкретно за тип сейчас используется и делать выборку со знакомыми тебе методами и параметрами, более того можешь сделать свой тип, унаследовать нужные интерфейсы и твой тип сможет точно так же взаимодействовать с linq запросами, любому другому человеку это будет понятнее и проще, чем разбираться с тем что ты можешь наворотить сам

Посмотри на реализацию любых плагинов или внешних библиотек. А еще лучше на какой-нибудь код на plain C в объектном стиле — там все потроха наружу.

Чтобы понять полезность интерфейсов нужно поработать в команде. А еще лучше в команде которая реализует только часть приложения и другую часть другая команда. И вам нужно использовать наработки другой команды а они используют ваши.

дає тобі не залежати від реалізації методу в клієнті.
щось на подобі цього

class Client
{
private ITopay
public Client(ITopay pay)
this.pay = pay
}
Тепер метод оплати буде обирати той хто створює клієнта.
Весь твій код може базуватися на роботі з інтерфейсом ITopay і пофіг яка реалізація

В твоём примере, лучше передавать объект, реализующий Topay в конструктор.

Соответственно тип параметра будет Topay, а дальше клиенту не важно это card, paypal или что-то ещё, он знает что объект реализует интерфейс и в нём точно есть метод pay.

Підписатись на коментарі