Яка різниця між нещільним з’єднанням і герметичним з’єднанням в об'єктно-орієнтованій парадигмі?


Відповіді:


338

Щільне з'єднання - це коли група класів сильно залежать один від одного.

Цей сценарій виникає, коли клас бере на себе занадто багато обов'язків або коли одна стурбованість поширюється на багато класів, а не на власний клас.

Вільне з'єднання досягається за допомогою конструкції, яка сприяє одноосібній відповідальності та відокремленню проблем.

Клас із слабким сполученням можна споживати та перевіряти незалежно від інших (конкретних) класів.

Інтерфейси - це потужний інструмент, який можна використовувати для роз'єднання. Класи можуть спілкуватися через інтерфейси, а не інші конкретні класи, і будь-який клас може бути на іншому кінці цього спілкування, просто реалізуючи інтерфейс.

Приклад герметичного з'єднання:

class CustomerRepository
{
    private readonly Database database;

    public CustomerRepository(Database database)
    {
        this.database = database;
    }

    public void Add(string CustomerName)
    {
        database.AddRow("Customer", CustomerName);
    }
}

class Database
{
    public void AddRow(string Table, string Value)
    {
    }
}

Приклад сипучої муфти:

class CustomerRepository
{
    private readonly IDatabase database;

    public CustomerRepository(IDatabase database)
    {
        this.database = database;
    }

    public void Add(string CustomerName)
    {
        database.AddRow("Customer", CustomerName);
    }
}

interface IDatabase
{
    void AddRow(string Table, string Value);
}

class Database implements IDatabase
{
    public void AddRow(string Table, string Value)
    {
    }
}

Ще один приклад тут .


Поки що те, що ви сказали, має ідеальний сенс. Чи можете ви пояснити, як механізм з’єднання може стосуватися шаблону спостерігача?
Джим

1
Тут спостерігається схема спостерігачів: en.wikipedia.org/wiki/Observer_pattern . Оскільки клас Subject може підтримувати перелік класів, які успадковуються від 'Observer', не знаючи фактично конкретного типу цих класів, це приклад нещільного з’єднання. Тема не залежить від будь-яких її спостерігачів або їх внутрішніх проблем. Спостерігачі не залежать від Тематики чи будь-яких її проблем.
Джонатан

4
Інтерфейси Java - це інструменти, які можуть цьому допомогти. Однак вони не потрібні. Поняття програми в інтерфейсі, а не реалізація, означає програму для публічних методів / атрибутів (або тих, які призначені для використання зовнішніми абонентами, коли мови не підтримують модифікатори доступу, як-от C). Інтерфейс повинен виконувати цей побічний контракт, не змінюючи його. У мовах, що не мають модифікаторів доступу (наприклад, C), це означає лише використання опублікованих інтерфейсів / функцій і не потрапляння на ті, які призначені для внутрішнього використання, оскільки вони можуть змінюватися у міру необхідності для підтримки опублікованих функцій.
Білл Росмус

3
@jonathanconway дякую, сер, але обидва фрагменти коду роблять те саме: у чому ж тоді різниця між ними? тобто які переваги є у слабкому зчепленні?
BKSpurgeon

1
Я бачив (в основному) цей приклад і раніше. На мою думку, це не має значення лише за наявності багатьох типів баз даних, які збираються використовувати. Якщо ви плануєте мати лише один, то чи погано використовувати реалізацію безпосередньо, а потім пізніше, якщо вам потрібно буде вводити різні типи, а потім переробляти одноразове використання бази даних для використання інтерфейсу? Замість того, щоб додавати навантаження коду пластини котла, який, ймовірно, не потрібен?
Карлос Брібієскас

177

Пояснення без будь-якого коду

Короткий приклад:

Капелюх "нещільно пов'язаний" з тілом. Це означає, що ви можете легко зняти шапку, не вносячи жодних змін у особу / тіло. Коли ви можете це зробити, тоді у вас є "вільна муфта". Дивіться нижче для розробки.

Капелюх "нещільно пов'язаний" з тілом.  Це означає, що ви можете легко зняти шапку, не вносивши жодних змін у особу / тіло.  Віднесення зображення: https://pixabay.com/en/greeting-cylinder-chapeau-dignity-317250/

Щільна муфта (докладний приклад)

Подумайте про свою шкіру. Це прилипло до вашого тіла. Він підходить, як рукавичка. Але що робити, якщо ви хотіли змінити колір шкіри з білого на зелений? Чи можете ви уявити собі, як боляче було б відшаровувати шкіру, фарбувати її, а потім наклеювати її на тощо? Змінити шкіру складно, оскільки вона щільно приєднана до вашого тіла. Ви просто не можете легко вносити зміни. Вам доведеться принципово переробити людину, щоб зробити це можливим.

  • Ключовий пункт №1 : Іншими словами, якщо ви хочете змінити шкіру, ви також хотіли б змінити дизайн свого тіла , тому що обидва з'єднані між собою - вони щільно з'єднані.

Бог не був хорошим об'єктно-орієнтованим програмістом.

Вільна муфта (докладний приклад)

Тепер подумайте, як одягнутися вранці. Вам не подобається синій? Немає проблем: замість цього можна надіти червону сорочку. Це можна зробити легко і без особливих зусиль, оскільки сорочка насправді не пов’язана з вашим тілом так само, як зі шкірою. Сорочка не знає і не піклується про те, на якому тілі вона йде . Іншими словами, ви можете переодягатися, не змінюючи свого тіла.

  • Це ключовий момент №2. Якщо ти поміняєш сорочку, то ти не змушений міняти своє тіло - коли ти можеш це зробити, то у тебе нещільна муфта. Коли ви не можете цього зробити, то у вас міцна зв'язка.

Це основна концепція в двох словах.

Чому все це важливо?

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

Практичні приклади з’єднання при кодуванні

  • Приклади CSV / JSON / DB: Якщо хтось хоче їх виведення у файл CSV, а не JSON тощо, або якщо ви хочете перейти з MySQL на PostGreSQL, ви повинні мати можливість зробити ці зміни надзвичайно легко у своєму коді, не потребуючи перезапису весь клас і т.д. Тому що, як це неминуче в програмному забезпеченні, відбудуться зміни. Коли вони дійдуть, набагато простіше, якщо ваші частини коду будуть зв'язані нещільно.

  • Приклад автомобільних деталей: Якщо хтось хоче, щоб їх автомобіль був у чорному , ви не повинні перебудувати всю машину для того , щоб зробити це. Автомобіль та його запчастини були б ідеальним прикладом слабко поєднаної архітектури. Якщо ви хочете замінити двигун на кращий, вам слід мати змогу просто вийняти двигун без особливих зусиль і поміняти його на кращий. Якщо ваш автомобіль працює тільки з двигунами Rolls Royce 1234 і немає інших двигунів, то ваш автомобіль буде щільно пов'язаний з цим двигуном (Rolls Royce 1234). Було б краще, якби ви змінили дизайн свого автомобіля, щоб він працював з будь-якимдвигун, так що він трохи вільніше поєднується з його компонентами. Ще краще, якби ваш автомобіль міг працювати, не потребуючи двигуна взагалі! Деяка кількість з’єднань відбудеться, але ви повинні працювати над тим, щоб мінімізувати її наскільки це можливо. Чому? Тому що, коли вимоги змінюються, ми все-таки зможемо доставити якісне програмне забезпечення, дуже швидко, і нам допомагають у цій цілі нещільною зв'язкою.

Підсумок

Коротше кажучи, нещільне з'єднання полегшує зміну коду. Наведені вище відповіді містять код, який варто прочитати на даний момент.

Поліморфізм та тверді принципи

Re: @TimoHuovinen коментує - концепція вільної зв'язку пов'язана з поняттями поліморфізму. Якщо ви зрозумієте основні аналоги сорочки / деталей автомобіля, тоді ви будете готові осмислити поліморфізм. Найкраще на даний момент - прочитати зразки коду, надані моїми оцінними колегами, в інших відповідях на цій темі. Якщо я скажу більше, ви можете перевантажитись надто великою кількістю інформації.

Зображення Attribution .


8
це таке занижене пояснення для нових програмістів. Важко пережити великі слова, які ми викладаємо з інших, коли ви зрозумієте основи, то легше перейти до великих слів lol
user2763557

6
Є деякі речі, які повинні бути щільно з'єднані, а деякі вільно пов'язані з оточенням. Використання шкіри не є належною аналогією для щільного зчеплення. Якщо вважається, що шкіра щільно поєднана з тілом, то це стосується і кожної іншої частини. Тіло (в цілому) повинно мати частини (щільно інтегровані), щоб нормально функціонувати (можливо, як думає природа - геніальний архітектор). Якщо ці частини були розроблені як замінні (такі ж прості, як зміна капелюха), то саме значення людського тіла втрачає своє визначення. Коментар 1/2.
lupchiazoem

6
Ідучи прикладом, якщо шкіра зроблена заміною, то голова також повинна бути замінена наново. Якщо це станеться, люди можуть бути не впізнавані від однієї зустрічі до іншої. Гарною аналогією з міцною / нещільною муфтою було б - автомобіль та його деталі, комп'ютер та його частини тощо. Якщо є проблема з мишею / клавіатурою комп'ютера, її можна замінити іншою частиною, а не робити цілий комп’ютер марним. і викинути. Коментар 2/2.
lupchiazoem

1
@BKSpurgeon Дивовижне пояснення !! і ваш спосіб взяти приклад для пояснення теж справді хороший.
Кіран Джоші

5
Пояснили дуже креативно. Я тісно пов'язаний з цією відповіддю.
AliN11

72

В об'єктно-орієнтованому дизайні кількість з’єднання відноситься до того, наскільки конструкція одного класу залежить від конструкції іншого класу. Іншими словами, як часто в класі В змінюються зміни сили класу А? Щільне зчеплення означає, що два класи часто змінюються разом, а вільне з'єднання означає, що вони здебільшого незалежні. Взагалі рекомендується розпушувальна муфта, тому що її простіше перевірити та підтримувати.

Ви можете знайти цей документ на Мартіна Фаулера (PDF) корисно.


"як часто в класі B відбуваються зміни класу A?" Мені потрібен короткий приклад для вищезгаданого речення ??
Kumaresan Perumal

15

Загалом, міцна муфта погана, але більшу частину часу, оскільки вона зменшує гнучкість та повторну використання коду, значно ускладнює зміни, перешкоджає перевірку і т.д.

Щільно пов'язаний об'єкт - це об'єкт, який потрібно знати трохи один про одного і зазвичай сильно залежить від інтерфейсів один одного. Зміна одного об'єкта в щільно зв'язаному додатку часто вимагає змін у ряді інших об'єктів. У невеликому додатку ми можемо легко визначити зміни, і є менше шансів пропустити що-небудь. Але у великих програмах ці взаємозалежності не завжди відомі кожному програмісту, або є шанс пропустити зміни. Але кожен набір зв'язаних об'єктів не залежить від інших.

Якщо коротко сказати, нещільне з'єднання - це ціль проектування, яка спрямована на зменшення взаємозалежності між компонентами системи з метою зменшення ризику, що зміни одного компонента потребують змін у будь-якому іншому компоненті. Розпущене з'єднання - це набагато більш загальна концепція, яка має на меті збільшити гнучкість системи, зробити її більш рентабельною та зробити всю основу більш «стабільною».

Сполучення стосується ступеня прямого знання, яке має один елемент іншого. ми можемо сказати, наприклад: A і B, тільки B змінює свою поведінку лише тоді, коли A змінює свою поведінку. Сильно пов'язана система може бути легко розбита на визначені елементи.


11

Коли два об'єкти зв'язані між собою, вони можуть взаємодіяти, але дуже мало знають один одного.

Мало сполучені конструкції дозволяють нам будувати гнучкі системи OO, здатні впоратися зі змінами.

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


6

Виписка з моєї публікації в блозі про з'єднання:

Що таке щільна муфта : -

Як і вище визначення, Об'єкт щільно пов'язаний - це об'єкт, який повинен знати про інші об'єкти і зазвичай сильно залежить від інтерфейсів один одного.

Коли ми змінюємо один об’єкт у щільно зв'язаному додатку, він часто вимагає змін до ряду інших об'єктів. У невеликій програмі немає жодної проблеми, і ми можемо легко визначити зміни. Але у випадку великих застосувань ці взаємозалежності не завжди відомі кожному споживачеві чи іншим розробникам, або є багато шансів на подальші зміни.

Візьмемо демо-код кошика, щоб зрозуміти тугий зв'язок:

namespace DNSLooseCoupling
{
    public class ShoppingCart
    {
        public float Price;
        public int Quantity;

        public float GetRowItemTotal()
        {
            return Price * Quantity;
        }
    }

    public class ShoppingCartContents
    {
        public ShoppingCart[] items;

        public float GetCartItemsTotal()
        {
            float cartTotal = 0;
            foreach (ShoppingCart item in items)
            {
                cartTotal += item.GetRowItemTotal();
            }
            return cartTotal;
        }
    }

    public class Order
    {
        private ShoppingCartContents cart;
        private float salesTax;

        public Order(ShoppingCartContents cart, float salesTax)
        {
            this.cart = cart;
            this.salesTax = salesTax;
        }

        public float OrderTotal()
        {
            return cart.GetCartItemsTotal() * (2.0f + salesTax);
        }
    }
}

Проблеми з наведеним вище прикладом

Щільне зчеплення створює певні труднощі.

Тут OrderTotal()методи дають нам повну суму для поточних предметів візка. Якщо ми хочемо додати функції знижок у цій кошиковій системі. Зробити вищезазначений код дуже важко, тому що нам доводиться вносити зміни в кожному класі, оскільки він дуже щільно пов'язаний.


6

Вільне сполучення означає, що ступінь залежності між двома компонентами дуже низький.
Приклад: GSM SIM

Щільне з'єднання означає, що ступінь залежності між двома компонентами дуже високий.
Приклад: CDMA Mobile


5

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

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


5

Щільне з'єднання означає, що один клас залежить від іншого класу.
Loose Coupling означає, що один клас залежить від інтерфейсу, а не від класу.

У тісному з'єднанні є твердо кодована залежність, заявлена ​​методами.
У нещільній муфті ми повинні переходити залежність зовні під час виконання замість жорсткого кодування. (Сипучі системи використовують інтерфейс для зменшення залежності від класу.)

Наприклад, у нас є система, яка може надсилати вихід двома або більше способами, такими як вихід JSON, вихід CSV тощо.

Щільно спарений

public interface OutputGenerator {
    public void generateOutput();
}

public class CSVOutputGenerator implements OutputGenerator {
    public void generateOutput() {
        System.out.println("CSV Output Generator");
    }
}

public class JSONOutputGenerator implements OutputGenerator {
    public void generateOutput() {
        System.out.println("JSON Output Generator");
    }
}

// In Other Code, we write Output Generator like...
public class Class1 {
    public void generateOutput() {
        // Here Output will be in CSV-Format, because of hard-coded code.
        // This method tightly coupled with CSVOutputGenerator class, if we want another Output, we must change this method.
        // Any method, that calls Class1's generateOutput will return CSVOutput, because Class1 is tight couple with CSVOutputGenerator.
        OutputGenerator outputGenerator = new CSVOutputGenerator();
        output.generateOutput();
    }
}

У наведеному вище прикладі, якщо ми хочемо змінити вихід у JSON, тоді нам потрібно знайти та змінити весь код, тому що Class1 щільно поєднаний з класом CSVOutputGenerator.

Вільно з'єднані

public interface OutputGenerator {
    public void generateOutput();
}

public class CSVOutputGenerator implements OutputGenerator {
    public void generateOutput() {
        System.out.println("CSV Output Generator");
    }
}

public class JSONOutputGenerator implements OutputGenerator {
    public void generateOutput() {
        System.out.println("JSON Output Generator");
    }
}

// In Other Code, we write Output Generator like...
public class Class1 {
    public void generateOutput(OutputGenerator outputGenerator) {
        // if you want to write JSON, pass object of JSONOutputGenerator (Dependency will be passed externally to this method)
        // if you want to write CSV, pass object of CSVOutputGenerator (Dependency will be passed externally to this method)

        // Due to loose couple with class, we don't need to change code of Class1, because Class1 is loose coupled with CSVOutputGenerator or JSONOutputGenerator class
        // Any method, that calls Class1's generateOutput will desired output, because Class1 does not tight couple with CSVOutputGenerator or JSONOutputGenerator class
        OutputGenerator outputGenerator = outputGenerator;
        output.generateOutput();
    }
}

3

Існують певні інструменти, які забезпечують введення залежності через свою бібліотеку, наприклад, у .net ми маємо бібліотеку ninject .

Якщо ви їдете далі в java, тоді весна надає ці можливості.

Нещільно пов'язані об'єкти можна зробити, ввівши інтерфейси у свій код, ось що роблять ці джерела.

Скажіть у своєму коді, який ви пишете

Myclass m = new Myclass();

тепер це твердження у вашому методі говорить про те, що ви залежні від myclassцього, називається тісно пов'язаним. Тепер ви надаєте деяку інжекцію конструктора, або об'єкт введення властивостей та інстанціювання, тоді він стане нещільно пов'язаним.


3

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

Щільна муфта

Щільне з'єднання було б очей. Якщо я хочу виправити своє бачення, мені дуже дорого зробити трансплантацію ока, і це ризик. Але що робити, якщо дизайнер (будучи людською расою) знайшов кращий спосіб. Додайте функцію, яка вільно з'єднана з тілом, щоб її можна було легко змінити! (так .. окуляри)

Вільна муфта

Я можу легко замінити окуляри, не порушуючи основного бачення. Я можу зняти окуляри, і моє бачення буде таким, як було раніше (ні краще, ні гірше). Використання різних пар окулярів змінює те, як ми бачимо світ своїми очима з невеликим ризиком і легким обслуговуванням.

Підсумок

Тож наступного разу хтось запитає у вас "кому все одно, чи мій код щільно пов'язаний?" Відповідь - це зусилля на зміну, зусилля щодо підтримання та ризик змін.

То як це робиться в C #? Інтерфейси та введення залежностей!

EDIT

Це гарний приклад малюнка Decorator, коли очі - це клас, який ми прикрашаємо, відповідаючи вимогам інтерфейсу, але надаючи різні функціональні можливості (наприклад, сонцезахисні окуляри, окуляри для читання, лупи для ювелірів тощо)


2

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

Loose Coupling = IoC Дивіться це для більш легкого пояснення.


3
Я не думаю, що нещільне з'єднання - це не те, що інверсія управління. Інверсія управління є дуже корисною технікою для зменшення стику вашої конструкції, але існує багато інших методик.
Дон Кіркбі

2

Loose Coupling - це процес надання залежності, якому ваш клас потребує опосередковано, не надаючи всієї інформації залежності (тобто від інтерфейсу) у випадку, якщо щільне з’єднання ви безпосередньо даєте залежність, що не є хорошим способом кодування.


2

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


1

Якщо створення / існування об'єкта залежить від іншого об'єкта, який неможливо налаштувати, його щільне з'єднання. І, якщо залежність може бути пристосована, її нещільне з'єднання. Розглянемо приклад на Java:

class Car {

    private Engine engine = new Engine( "X_COMPANY" ); // this car is being created with "X_COMPANY" engine
    // Other parts

    public Car() { 
        // implemenation 
    }

}

Клієнт Carкласу може створити його за допомогою ТОЛЬКО двигуна "X_COMPANY".

Розглянемо розрив цього з’єднання зі здатністю змінити це:

class Car {

    private Engine engine;
    // Other members

    public Car( Engine engine ) { // this car can be created with any Engine type
        this.engine = engine;
    }

}

Тепер, a Carне залежить від двигуна "X_COMPANY", оскільки його можна створити з типами.

Примітка, що стосується Java: використання інтерфейсів Java лише заради роз'єднання зв'язку не є правильним підходом до проекту. У Java інтерфейс має свою мету - діяти як договір, який внутрішньо передбачає поведінку / перевагу роз'єднання.

Коментар Білла Росмуса у прийнятій відповіді має гарне пояснення.


0

Щільне зчеплення означає, що класи та об'єкти залежать один від одного. Взагалі, герметичне з'єднання, як правило, не добре, оскільки це зменшує гнучкість та повторну використання коду, тоді як Loose-з'єднання означає зменшення залежності класу, який безпосередньо використовує інший клас.

Щільне з'єднання Щільно пов'язаний об'єкт - це об'єкт, який повинен знати про інші об'єкти і зазвичай сильно залежить від інтерфейсів один одного. Зміна одного об'єкта в щільно зв'язаному додатку часто вимагає змін у ряді інших об'єктів. У невеликих додатках ми можемо легко визначити зміни, і є менше шансів пропустити що-небудь. Але у великих програмах ці взаємозалежності не завжди відомі кожному програмісту, і є ймовірність не помітити зміни. Приклад:

    class A {
       public int a = 0;
       public int getA() {
          System.out.println("getA() method");
          return a;
       }
       public void setA(int aa) {
          if(!(aa > 10))
             a = aa;
       }
    }
    public class B {
       public static void main(String[] args) {
          A aObject = new A();
          aObject.a = 100; // Not suppose to happen as defined by class A, this causes tight coupling.
          System.out.println("aObject.a value is: " + aObject.a);
       }
    }

In the above example, the code that is defined by this kind of implementation uses tight coupling and is very bad since class B knows about the detail of class A, if class A changes the variable 'a' to private then class B breaks, also class A's implementation states that variable 'a' should not be more than 10 but as we can see there is no way to enforce such a rule as we can go directly to the variable and change its state to whatever value we decide.

    Output
    aObject.a value is: 100

Loose Coupling
Loose coupling is a design goal to reduce the inter-dependencies between components of a system with the goal of reducing the risk that changes in one component will require changes in any other component.
Loose coupling is a much more generic concept intended to increase the flexibility of the system, make it more maintainable and makes the entire framework more stable.
Example:

class A {
   private int a = 0;
   public int getA() {
      System.out.println("getA() method");
      return a;
   }
   public void setA(int aa) {
      if(!(aa > 10))
         a = aa;
   }
}
public class B {
   public static void main(String[] args) {
      A aObject = new A();
      aObject.setA(100); // No way to set 'a' to such value as this method call will
                         // fail due to its enforced rule.
      System.out.println("aObject value is: " + aObject.getA());
   }
}

У наведеному вище прикладі код, який визначається цим способом реалізації, використовує розв'язане з'єднання і рекомендується, оскільки клас B повинен пройти клас А, щоб отримати його стан, коли правила застосовуються. Якщо клас A змінюється внутрішньо, клас B не порушується, оскільки він використовує лише клас A як спосіб спілкування.

Output
getA() method
aObject value is: 0
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.