Що таке "нещільна муфта"? Наведіть приклади


172

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

Хтось покаже, будь ласка, якийсь код "до" та "після" (або псевдокод), який ілюструє це поняття?


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

11
Повністю не погоджуючись, практичні можливості можна проілюструвати по-різному на різних мовах, і це особливо очевидно в динамічній та компільованій мовах. Але концепція в будь-якому випадку однакова.
Оуен

Loose vs Tight та Coupling vs отделить . Дотримуватись цього не завжди добре, іноді добре / іноді не добре ... Як ми повинні мати власну незалежність , так і заняття.
bonCodigo

Відповіді:


180

Розглянемо просту програму кошика, яка використовує клас CartContents для відстеження предметів у кошику для покупок та клас замовлення для обробки покупки. Порядок повинен визначити загальне значення вмісту в кошику, він може зробити так:

Приклад щільно з'єднаного:

public class CartEntry
{
    public float Price;
    public int Quantity;
}

public class CartContents
{
    public CartEntry[] items;
}

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

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

    public float OrderTotal()
    {
        float cartTotal = 0;
        for (int i = 0; i < cart.items.Length; i++)
        {
            cartTotal += cart.items[i].Price * cart.items[i].Quantity;
        }
        cartTotal += cartTotal*salesTax;
        return cartTotal;
    }
}

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

Тепер ось трохи кращий спосіб зробити те ж саме:

Приклад менш сполучений:

public class CartEntry
{
    public float Price;
    public int Quantity;

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

public class CartContents
{
    public CartEntry[] items;

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

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

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

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

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


Чи можете ви розширити відповідь, запровадивши подальшу розв'язку через введення залежності (хоча конструктор повинен бути ідеальним)?
BAD_SEED

4
@Wedge, я не бачу причин для того, Orderщоб мати будь-які знання про Cart. Покупки в прямому ефірі та факти - це два різних контексти. Коли клієнт готовий платити, у вас може виникнути процес перекладати CartEntries у щось важливе для цього Order. Таким чином, Orderклас також буде інстанційним та використаний без а Cart.
plalx

@Wedge Чи можете ви відреагувати на мій коментар?
plalx

Ну і просто пояснили. Я почав бачити світло в "..Помітьте про те, як залежить метод OrderTotal (і, таким чином, клас замовлення), залежно від деталей про реалізацію класів CartContents та CartEntry".
okey_on

Цей приклад чітко представлений. Однак в наші дні все більше архітекторів сходяться на думці, що цей занадто об'єктно-орієнтований стиль є поганою практикою. Немає сенсу приховувати "деталі" реалізації CartEntryта CartContents. Оскільки вони мають цілком чітке значення, їх слід просто моделювати як мертві дані. З точки зору бази даних, все, що тут потрібно, - це таблицяCREATE TABLE entry (price INTEGER, quantity INTEGER)
Jo So

160

Багато інтегрованих продуктів (особливо Apple), таких як iPod , iPad - хороший приклад тісного з’єднання: коли акумулятор вмирає, ви також можете придбати новий пристрій, оскільки акумулятор паяний фіксованим і не втрачається, що робить заміну дуже дорого. Слабо пов'язаний плеєр дозволить без особливих зусиль міняти акумулятор.

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


Чи хороша вільна або щільна муфта? Як прийняти рішення про реалізацію нещільної муфти або герметичної муфти?
Sreekanth Karumanaghat

2
дякую за цей чудовий приклад. Я витратив багато часу на інші відповіді, але не варто, як це
аламін

1
Sreekanth Karumanaghat, ви б краще витратили менше грошей лише на акумулятор і знову працювали iPod, або хотіли б витратити багато грошей на цілий iPod?
Кошера

1
@SreekanthKarumanaghat Типово нещільне з'єднання краще, оскільки воно сприяє модульності і тим самим полегшує підтримку коду. Якщо ви щільно з'єднаєте свої класи / бібліотеки / код, то будь-яку невелику зміну, внесену в один клас, доведеться здійснити у всіх класах, які ним користуються.
Кенні Worden

56

Я буду використовувати приклад Java. Скажімо, у нас є клас, який виглядає приблизно так:

public class ABC
{
   public void doDiskAccess() {...}
}

Коли я дзвоню в клас, мені потрібно буде зробити щось подібне:

ABC abc = new ABC();

abc. doDiskAccess();

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

public class XYZ
{
   public void doNetworkAccess() {...}
}

Він виглядає точно так само, як ABC, але скажімо, він працює через мережу, а не на диску. Тому тепер давайте напишемо програму так:

if(config.isNetwork()) new XYZ().doNetworkAccess();
else new ABC().doDiskAccess();

Це працює, але це трохи громіздко. Я міг би спростити це за допомогою такого інтерфейсу:

public interface Runnable
{
    public void run();
}

public class ABC implements Runnable
{
   public void run() {...}
}

public class XYZ implements Runnable
{
   public void run() {...}
}

Тепер мій код може виглядати так:

Runnable obj = config.isNetwork() ? new XYZ() : new ABC();

obj.run();

Подивіться, наскільки чистіше і простіше це зрозуміти? Ми щойно зрозуміли перший основний принцип нещільної зв'язку: абстракція. Головне звідси - переконатися, що ABC та XYZ не залежать від будь-яких методів чи змінних класів, які їх викликають. Це дозволяє ABC та XYZ бути повністю незалежними API. Або іншими словами, вони "роз'єднані" або "нещільно пов'язані" з батьківських класів.

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


2
Цей приклад все ще має досить високий рівень зв'язку. Щойно тепер замість того, щоб з'єднуватися в один клас, можна вибрати два. Цей приклад передбачає, що буде доступно лише дві реалізації "Runnable". У такому випадку інтерфейс навіть не потрібен.
Оуен

Ці методи з ім'ям Run * і Do * - для мене величезний запах коду. Ви також можете скористатися цим використанням IHandleStuff або IFrobnicateThings. У цьому випадку термін, який можна виконати, є занадто загальним терміном.
Клин

8
Оуен, дитина крокує до мого друга. Якщо він не розуміє з'єднання, як він зрозуміє, який заводський зразок купує його? Цей приклад коду ставить його на правильний шлях. Завдання полягає в тому, щоб він краще зрозумів проблему і зрозумів, як абстрагувати створення об'єктів.
64BitBob

6
Чи було б це читабельніше, якби ABC та XYZ були перейменовані на щось подібне DiskAccessorі NetworkAccessor? I dunno no java ...
MusiGenesis

Чи він також використовує заводський шаблон дизайну? Тому що ми створюємо нові об'єкти XYZ або ABC залежно від потреби.
munmunbb

37

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

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

Висока згуртованість на зразок «щільного з’єднання», але висока згуртованість - це стан, коли елементи дизайну, які дійсно повинні знати один про одного, розроблені так, щоб вони працювали разом чітко та елегантно.

Справа в тому, що деякі елементи дизайну повинні знати деталі щодо інших елементів дизайну, тому вони повинні бути спроектовані саме так, а не випадково. Інші елементи дизайну не повинні знати деталі щодо інших елементів дизайну, тому вони повинні бути спроектовані таким чином, цілеспрямовано, а не випадковим чином.

Реалізація цього залишається як вправа для читача :).


33

Щільно пов'язаний код покладається на конкретну реалізацію. Якщо мені потрібен список рядків у моєму коді, і я оголошую його так (на Java)

ArrayList<String> myList = new ArrayList<String>();

то я залежу від реалізації ArrayList.

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

List<String> myList = new ArrayList<String>();

Це не дозволяє мені викликати будь-який методmyList який є специфічним для реалізації ArrayList. Я обмежений лише тими методами, визначеними в інтерфейсі List. Якщо згодом я вирішу, що мені дійсно потрібен LinkedList, мені потрібно змінити код лише в одному місці, де я створив новий Список, а не в 100 місцях, де я робив дзвінки методами ArrayList.

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


Це навряд чи стосується того, що насправді є "зчепленням" . Дивіться stackoverflow.com/questions/39946/coupling-and-cogery, щоб отримати кілька хороших відповідей.
Rogério

@Rogerio: Я думаю, що це стосується. Може бути , ви збентежені іншими визначеннями «зв'язку» , але ви , ви повинні прочитати слабосвязанності . "Сильне з'єднання відбувається, коли залежний клас містить вказівник безпосередньо на конкретний клас, який забезпечує необхідну поведінку ... Вільне сполучення відбувається, коли залежний клас містить вказівник лише на інтерфейс, який потім може бути реалізований одним або багатьма конкретними класами . " У моєму прикладі мій код буде слабко пов'язаний з ArrayList через інтерфейс List.
Білл Ящірка

@Bill: Дякую за посилання, але ця стаття мені здається абсолютно хибною. Схоже, "переосмислюються" ідеї з іншої галузі (організаційна поведінка), даючи визначення "вільної зв'язку", що суперечить оригінальному специфічному програмному визначенню Ларрі Константина: en.wikipedia.org/wiki/Coupling_(computer_science) .
Rogério

@ Роджеріо: Стаття Костянтина була написана в 1974 році. Цілком ймовірно, що за останні 36 років було багато переосмислень, але я не думаю, що стаття у Вікіпедії є її джерелом. Наприклад, шаблони на зразок впорскування залежностей покладаються на інтерфейси для послаблення зв'язку так само, як я описую у своїй відповіді.
Білл Ящірка

2
@Bill: Звичайно, робота Костянтина над «Структурованим дизайном» - це старий матеріал, але я не бачу жодної причини, щоб його визнати недійсним або радикально переосмислити. Оригінальні концепції згуртованості та з'єднання лежать в основі об'єктно-орієнтованого дизайну, так само, як і спадщина та поліморфізм. DI (краща стаття - martinfowler.com/articles/injection.html ) - це лише техніка зовнішньої конфігурації плагінів (абстрактні інтерфейси з реалізаціями, вибраними під час виконання через конфігураційний код); Ще одна така методика - це шаблон локатора послуг. DI та з'єднання - незалежні поняття.
Rogério

27

Ступінь різниці між відповідями тут показує, чому це було б важко зрозуміти, але сказати так просто, як я можу описати:

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

За допомогою нединамічних мов, таких як c # або Java тощо, ми досягаємо цього за допомогою інтерфейсів. Тож скажемо, у нас є такий інтерфейс:

public ICatcher
{
   public void Catch();
}

А тепер скажемо, що у нас є такі класи:

public CatcherA : ICatcher
{
   public void Catch()
   {
      console.writeline("You Caught it");
   }

}
public CatcherB : ICatcher
{
   public void Catch()
   {
      console.writeline("Your brother Caught it");
   }

}

Тепер і CatcherA, і CatcherB реалізують метод Catch, тож сервіс, який вимагає Catcher, може використовувати будь-який із них, а не справді проклятий, який це. Таким чином, щільно пов'язана послуга може безпосередньо створити схоплений, тобто

public CatchService
{
   private CatcherA catcher = new CatcherA();

   public void CatchService()
   {
      catcher.Catch();
   }

}

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

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

public CatchService
{
   private ICatcher catcher;

   public void CatchService(ICatcher catcher)
   {
      this.catcher = catcher;
      catcher.Catch();
   }
}

Таким чином, calss, який встановлює CatchService, може робити наступне:

CatchService catchService = new CatchService(new CatcherA());

або

CatchService catchService = new CatchService(new CatcherB());

Це означає, що служба Catch не є щільно пов'язаною ні з CatcherA, ні з CatcherB.

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


1
Цей приклад мені подобається краще, ніж інші, оскільки подібні речі відбуваються в діловому світі щодня. Якщо працює Особа Класу, працює Кішка Класу, Бігає Клас Собака тощо. Це була б величезна програма з деталізацією всіх цих класів. Але використання інтерфейсу під назвою запуску, де кожен клас робить те саме, робить вашу програму набагато гнучкішою та керованою. :)
sksallaj

Пояснив дійсно добре, пане, лише щоб зрозуміти, що в останньому прикладі ви зробили це з введенням залежності, і перший приклад також нещільно пов'язаний?
Алі Садід

Ого, стара відповідь прокоментувала :). Отже, відповідь "ні", перший приклад має жорстку залежність від CatcherA, тому вони сильно пов'язані
Оуен

23

Ви можете подумати про (тугий або нещільний) зв'язок як про буквально таку кількість зусиль, яка знадобиться вам, щоб відокремити певний клас від його опори на інший клас. Наприклад, якщо кожен метод у вашому класі мав остаточний блок у нижній частині, де ви телефонували до Log4Net, щоб щось увійти, тоді ви б сказали, що ваш клас був щільно пов'язаний з Log4Net. Якщо ваш клас замість цього містив приватний метод під назвою LogSomething, який був єдиним місцем, яке викликало компонент Log4Net (а інші методи замість нього називали LogSomething), то ви б сказали, що ваш клас був зв'язаний з Log4Net (тому що це не займе багато намагання витягнути Log4Net і замінити його чимось іншим).


1
Отже, "нещільно пов'язане" насправді означає менше залежностей? Я прав?
користувач314362

4
Це насправді не пов'язане із загальною кількістю залежностей одного конкретного класу. Зчеплення (щільне або вільне) насправді є властивістю відносин між двома класами. Таким чином, у вас може бути один клас, який слабко пов'язаний з 100 іншими класами, або інший клас, який щільно пов'язаний з двома іншими класами (наприклад).
MusiGenesis

2
Поганий приклад, я б сказав: у вас є дублювання коду, а не жорстке з'єднання. І за допомогою хорошого інструменту рефакторингу таке дублювання можна усунути за лічені секунди.
Rogério

@Rogerio: це, мабуть, не найкращий приклад. Мені подобається 64BitBobкраще відповідь.
MusiGenesis

12

Визначення

По суті, з'єднання - це те, наскільки даний об'єкт або набір об'єкта покладається на інший об'єкт або інший набір об'єктів для виконання своєї задачі.

Висока муфта

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

Вільна муфта

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


7

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

Один хлопець тут, на роботі, сказав мені: "візерунки схожі на фрактали, їх можна побачити, коли ви збільшуєте зусилля дуже близько і коли ви збільшуєте масштаб до рівня архітектури".

Прочитавши коротку сторінку вікіпедії, ви можете відчути цю загальність:

http://en.wikipedia.org/wiki/Loose_coupling

Що стосується конкретного прикладу коду ...

Ось одна нещільна муфта, з якою я нещодавно працював, з матеріалів Microsoft.Practices.CompositeUI.

    [ServiceDependency]
    public ICustomizableGridService CustomizableGridService
    {
        protected get { return _customizableGridService; }
        set { _customizableGridService = value; }
    }

Цей код заявляє, що цей клас має залежність від CustomizableGridService. Замість того, щоб безпосередньо посилатися на точну реалізацію послуги, вона просто заявляє, що вона потребує ДЕЯКОЇ реалізації цієї послуги. Потім під час виконання система вирішує цю залежність.

Якщо це не зрозуміло, ви можете прочитати більш детальне пояснення тут:

http://en.wikipedia.org/wiki/Dependency_injection

Уявіть, що ABCCustomizableGridService - це імплементація, яку я маю намір підключити тут.

Якщо я вирішу, я можу витягнути це і замінити його на XYZCustomizableGridService або StubCustomizableGridService, не змінюючи класу зовсім із цією залежністю.

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


6

Зв'язок пов'язаний із залежностями між системами, які можуть бути модулями коду (функції, файли або класи), інструментами в конвеєрі, процесами сервер-клієнт тощо. Чим менше загальних залежностей, тим вони "щільніше пов'язані", оскільки зміна однієї системи вимагає зміни інших систем, які на неї покладаються. Ідеальною ситуацією є "нещільне з'єднання", коли одну систему можна змінити, а системи залежно від неї продовжуватимуть працювати без змін.

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

Деякі приклади:

  • Застосування залежить від бібліотеки. За умови жорсткого з’єднання додаток працює на новіших версіях ліб. Google для "Пекло DLL".

  • Клієнтська програма читає дані з сервера. В умовах жорсткого з'єднання зміни для сервера вимагають виправлень на стороні клієнта.

  • Два класи взаємодіють в об'єктно-орієнтованій ієрархії. За умови чіткого з'єднання зміни одного класу вимагають оновлення іншого класу для відповідності.

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


5

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

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

Legos, іграшки, які SNAP разом, вважатимуться зв'язаними, тому що ви можете просто зв'язати шматочки разом і створити будь-яку систему, яку ви хочете. Однак головоломка має шматки, які ТІЛЬКО з'єднані. Ви не можете взяти шматок із однієї головоломки (системи) і перерізати її в іншу головоломку, тому що система (головоломка) дуже залежить від тих самих специфічних фігур, які були побудовані саме для цієї конкретної «конструкції». Легос побудований більш загальним чином, щоб їх можна було використовувати у вашому будинку Лего, або в моїй Лего Чужій людині.

Довідка: https://megocode3.wordpress.com/2008/02/14/coupling-and-cogery/


4

Два компоненти сильно пов'язані між собою, коли вони залежать від конкретного впровадження один одного.

Припустимо, я маю цей код десь у методі у своєму класі:

this.some_object = new SomeObject();

Тепер мій клас залежить від SomeObject, і вони сильно поєднані. З іншого боку, скажімо, у мене є метод InjectSomeObject:

void InjectSomeObject(ISomeObject so) { // note we require an interface, not concrete implementation
  this.some_object = so;
}

Тоді перший приклад може просто використовувати введений SomeObject. Це корисно під час тестування. У звичайній роботі ви можете використовувати важкі класи, що використовують бази даних, заняття з мережею тощо, в той час як для тестів, що проходять легку, макетну реалізацію. З щільно сполученим кодом ви цього не можете зробити.

Можна зробити деякі частини цієї роботи легшими, використовуючи контейнери для ін'єкцій залежностей. Більше про DI можна прочитати у Вікіпедії: http://en.wikipedia.org/wiki/Dependency_injection .

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


3

Розглянемо додаток для Windows з FormA та FormB. FormA - це первинна форма, і вона відображає FormB. Уявіть, що FormB потребує повернення даних батькові.

Якщо ви зробили це:

class FormA 
{
    FormB fb = new FormB( this );

    ...
    fb.Show();
}

class FormB 
{
    FormA parent;

    public FormB( FormA parent )
    {
        this.parent = parent;
    }     
}

FormB щільно з'єднаний з FormA. FormB не може мати іншого батьківського, ніж у типу FormA.

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

rp


3

В інформатиці є ще одне значення для "вільної зв'язку", про яке ніхто більше не публікував тут, так що ... Ось ідеться - сподіваємось, ви дасте мені трохи голосів, щоб це не було втрачено внизу купи! ВІДПОВІДНО Тема моєї відповіді належить до будь-якої вичерпної відповіді на запитання ... До розуму:

Термін "Loose Coupling" вперше ввів обчислення як термін, який використовується як прикметник щодо архітектури процесора в конфігурації декількох процесорів. Її аналогічним терміном є "герметичне з'єднання". Loose Coupling - це коли CPU не ділять багато спільних ресурсів, а Tight Coupling - це коли вони є.

Термін "система" тут може заплутати, тому, будь ласка, уважно проаналізуйте ситуацію.

Зазвичай, але не завжди, декілька процесорів в апаратній конфігурації, в якій вони існують в одній системі (як в окремих коробках "ПК"), були б щільно поєднані. За винятком деяких високоефективних систем, які мають підсистеми, які фактично діляться основною пам’яттю на «системи», всі розділяються системи слабко пов'язані.

Терміни Tightly Couple and Loosely Coupled були введені ще до того, як були винайдені багатопотокові та багатоядерні процесори, тому цим термінам можуть знадобитися деякі супутники, щоб повністю сформулювати ситуацію сьогодні. І дійсно, сьогодні цілком може бути система, яка охоплює обидва типи в одній загальній системі. Що стосується сучасних програмних систем, то існує дві загальні архітектури, по одній з яких є різноманітність, які є загальними, і вони повинні бути знайомими.

По-перше, оскільки з цього питання йшлося, кілька прикладів сильно зв'язаних систем:

  • VaxClusters
  • Кластери Linux

На відміну від деяких прикладів щільно з'єднаних:

  • Операційні системи «Семетрічна-багатообробка» (наприклад, Fedora 9)
  • Багатопотокові процесори
  • Багатоядерні процесори

У сучасних обчисленнях приклади обох функціонування в єдиній загальній системі не є рідкістю. Наприклад, візьміть сучасні парні чи чотирьохядерні процесори Pentium, що працюють під управлінням Fedora 9 - це щільно пов'язані обчислювальні системи. Потім об'єднайте декілька з них у зв'язаний кластер Linux, і тепер у вас є як вільно, так і щільно пов'язані обчислення! О, хіба сучасне обладнання не чудове!


3

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


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

е, не дуже корисно
бгр

2

Тут є кілька довгих відповідей. Однак принцип дуже простий. Я надсилаю вступне слово з wikipedia :

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

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


1
Якби це було так просто, у нас не було б цього обговорення.
бргс

2

Я пропоную дуже простий тест з’єднання коду :

  1. Шматок A коду щільно поєднаний з Елементом B коду, якщо є якась можлива модифікація Шматка B, яка змусить змінити Шматок А, щоб зберегти правильність.

  2. Шматок A коду не є щільно пов'язаним із шматочком B коду, якщо немає можливої ​​модифікації Piece B, яка б зробила необхідною зміну Piece A.

Це допоможе вам перевірити, скільки є з'єднань між фрагментами вашого коду. про міркування з цього питання дивіться цей запис у блозі: http://marekdec.wordpress.com/2012/11/14/loose-coupling-tight-coupling-decoupling-what-is-that-all-about/


2

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

--- А.java ---

package interface_package.loose_coupling;

public class A {

void display(InterfaceClass obji)
{
    obji.display();
    System.out.println(obji.getVar());
}
}

--- B.java ---

package interface_package.loose_coupling;

public class B implements InterfaceClass{

private String var="variable Interface";

public String getVar() {
    return var;
}

public void setVar(String var) {
    this.var = var;
}

@Override
public void display() {
    // TODO Auto-generated method stub
    System.out.println("Display Method Called");
}
}

--- InterfaceClass ---

package interface_package.loose_coupling;

public interface InterfaceClass {

void display();
String getVar();
}

--- MainClass ---

package interface_package.loose_coupling;

public class MainClass {

public static void main(String[] args) {
    // TODO Auto-generated method stub

    A obja=new A();
    B objb=new B();
    obja.display(objb);     //Calling display of A class with object of B class 

}
}

Пояснення:

У наведеному вище прикладі ми маємо два класи A і B

Клас B реалізує інтерфейс, тобто InterfaceClass.

InterfaceClass визначає контракт для класу B, оскільки InterfaceClass мають абстрактні методи класу B, до яких може бути доступ будь-який інший клас, наприклад, A.

У класі A у нас є метод відображення, який, крім об'єкта класу, який реалізує InterfaceClass (у нашому випадку це клас B). І на цьому об'єктному методі класу A є виклик display () та getVar () класу B

У MainClass ми створили об'єкти класів A і B. І викликаємо метод відображення A шляхом передачі об'єкта B класу, тобто objb. Метод відображення A буде викликаний з об'єктом класу B.

Зараз говоримо про сипучу муфту. Припустимо, у майбутньому вам доведеться змінити назву класу B на ABC, тоді вам не доведеться змінювати його ім'я в способі відображення класу B, просто зробіть об’єкт нового (клас ABC) і передайте його методу відображення в MailClass. Вам не потрібно нічого змінювати в класі А

посилання: http://p3lang.com/2013/06/loose-coupling-example-using-interface/


0

Ви можете прочитати докладніше про загальну концепцію "сипучої муфти" .

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


-8

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

Сподіваюся, це дещо корисно.


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

Стів, ти маєш ТОГО право - ти не заслужив жодного з голосів, що не були. Просто ваша аудиторія не була готова до вашої термінології, і занадто багато на цьому сайті мають звичку голосувати за те, що вони не розуміють, або те, що незнайоме. -shrug-
Річард T

Я думаю, що Стів пропустив справу. Вільне з'єднання не завжди означає, що два суб'єкти працюють незалежно на одному робочому навантаженні.
Роб
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.