В чем разница между слабой связью и сильной связью в объектно-ориентированной парадигме?


Ответы:


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)
    {
    }
}

Еще один пример здесь .


Пока то, что вы сказали, имеет смысл. Не могли бы вы объяснить, как механизм связи может относиться к шаблону Observer?
Джим

1
Шаблон наблюдателя описан здесь: en.wikipedia.org/wiki/Observer_pattern . Так как класс Subject может поддерживать список классов, которые наследуются от 'Observer', фактически не зная конкретный тип этих классов, это пример слабой связи. Субъект не зависит от своих наблюдателей или внутренних проблем. Наблюдатели не зависят от Субъекта или его интересов.
Джонатан

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

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

1
Я видел (в основном) этот пример раньше. По моему мнению, это не имеет значения, только если будет много типов баз данных, которые будут использоваться. Если вы планируете использовать только один, то плохо ли использовать реализацию напрямую, а потом, если вам понадобится внедрить разные типы, тогда рефакторинг единственного использования базы данных для использования интерфейса? Вместо того, чтобы добавлять нагрузки кода котельной плиты, который, вероятно, не нужен?
Карлос Брибьескас

178

Объяснение без ЛЮБОГО кода

Сводный пример:

Шляпа «слабо связана» с телом. Это означает, что вы можете легко снять шляпу, не внося никаких изменений в человека / тело. Когда вы можете сделать это, у вас есть «слабая связь». Смотрите ниже для уточнения.

Шляпа «слабо связана» с телом.  Это означает, что вы можете легко снять шляпу, не внося никаких изменений в человека / тело.  Атрибуция изображения: https://pixabay.com/ru/greeting-cylinder-chapeau-dignity-317250/

Герметичное соединение (подробный пример)

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

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

Бог не был хорошим объектно-ориентированным программистом.

Слабая связь (подробный пример)

А теперь подумай одеться утром. Тебе не нравится синий? Нет проблем: вместо этого вы можете надеть красную рубашку. Вы можете сделать это легко и без усилий, потому что рубашка на самом деле не связана с вашим телом так же, как ваша кожа. Рубашка не знает и не заботится о том, на каком она теле . Другими словами, вы можете сменить одежду, не меняя своего тела.

  • Это ключевой момент № 2. Если вы меняете свою рубашку, то вы не обязаны менять свое тело - когда вы можете это сделать, тогда у вас слабая связь. Когда вы не можете этого сделать, значит, у вас сильная связь.

Это основная концепция в двух словах.

Почему все это важно?

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

Практические примеры сцепления при кодировании

  • Примеры CSV / JSON / DB: Если кто-то хочет выводить его в CSV-файле, а не в JSON и т. Д., Или если вы хотите переключиться с MySQL на PostGreSQL, вы сможете сделать эти изменения очень легко в своем коде без необходимости переписывать весь класс и т. д. Другими словами, вы не хотите тесно связывать ваше приложение с конкретной реализацией базы данных (например, Mysql) или с конкретным выводом (например, CSV-файлы). Потому что, как это неизбежно в программном обеспечении, изменения придут. Когда они приходят, гораздо проще, если ваши части кода слабо связаны.

  • Пример автозапчастей: если кто-то хочет свою машину в черном цвете , вам не нужно переделывать всю машину, чтобы сделать это. Автомобиль и его запчасти были бы прекрасным примером слабо связанной архитектуры. Если вы хотите заменить свой двигатель на более качественный, вы сможете просто снять его без особых усилий и заменить его на лучший. Если ваш автомобиль работает только с двигателями Rolls Royce 1234 и без других двигателей - то ваш автомобиль будет тесно связан с этим двигателем (Rolls Royce 1234). Было бы лучше, если бы вы изменили дизайн своего автомобиля, чтобы он работал с любымдвигатель, так что он немного слабее связан с его компонентами. Еще лучше было бы, если бы ваша машина могла работать без двигателя вообще! Должна произойти некоторая связь, но вы должны стараться свести ее к минимуму. Зачем? Потому что, когда требования меняются, мы все равно должны иметь возможность поставлять качественное программное обеспечение, очень быстро, и нам помогает в этой цели слабая связь.

Резюме

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

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

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

Атрибуция изображения .


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

6
Есть некоторые вещи, которые должны быть тесно связаны, а некоторые - слабо связаны с окружающей средой. Использование кожи не является хорошей аналогией для плотного сцепления. Если кожа считается тесно связанной с телом, то и любая другая часть. Тело (в целом) должно иметь части (тесно интегрированные), чтобы функционировать должным образом (может быть, как думает природа - гениальный архитектор). Если эти части были разработаны для замены (так же просто, как смена шляпы), то само значение «человеческого» тела теряет свое определение. Комментарий 1/2.
lupchiazoem

6
Если следовать примеру, если кожа сделана сменной, то и голова должна быть заменена заново. Если это произойдет, то люди могут быть не узнаваемы от одного собрания к другому. Хорошая аналогия жесткой / слабой связи может быть - автомобиль и его части, компьютер и его части и т. Д. ... Если есть проблема с мышью / клавиатурой компьютера, ее можно заменить другой частью, а не сделать весь компьютер бесполезным и выбросить. Комментарий 2/2.
lupchiazoem

1
@BKSpurgeon Потрясающее объяснение !! и ваш способ взять пример для объяснения тоже очень хорош.
Киран Джоши

5
Объяснил очень творчески. Я тесно связан с этим ответом.
AliN11

72

В объектно-ориентированном дизайне величина связывания относится к тому, насколько дизайн одного класса зависит от дизайна другого класса. Другими словами, как часто изменения в классе A связаны с изменениями в классе B? Тесная связь означает, что два класса часто меняются вместе, слабая связь означает, что они в основном независимы. В целом, слабая связь рекомендуется, потому что ее легче тестировать и обслуживать.

Эта статья Мартина Фаулера (PDF) может оказаться полезной.


«Как часто изменения в классе А связаны с изменениями в классе В?» Мне нужен краткий пример для предложения выше?
Кумаресан Перумал

15

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

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

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

Связь означает степень непосредственного знания, которое один элемент имеет у другого. Например, мы можем сказать: A и B, только B меняет свое поведение, только когда A меняет свое поведение. Слабосвязанная система может быть легко разбита на определяемые элементы.


11

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

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

Шаблон проектирования Observer - хороший пример того, как сделать классы слабо связанными, вы можете посмотреть его в Википедии .


6

Выдержка из моего сообщения в блоге о связи:

Что такое жесткая муфта : -

Как указано выше, Tightly Coupled Object - это объект, который должен знать о других объектах и ​​обычно сильно зависит от интерфейсов друг друга.

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

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

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

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

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

Например, у нас есть система, которая может отправлять вывод двумя или более способами, такими как вывод 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, то Spring предоставляет эти возможности.

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

Скажи в своем коде вы пишете

Myclass m = new Myclass();

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


3

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

Тесная связь

Тесная связь была бы глазами. Если я хочу исправить свое зрение, мне очень дорого сделать пересадку глаза, и у меня довольно много риска. Но что, если дизайнер (будучи человеческой расой) нашел лучший путь? Добавьте функцию, которая слабо связана с корпусом, чтобы ее можно было легко изменить! (да .. очки)

Слабая связь

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

Резюме

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

Так как же это сделать в C #? Интерфейсы и внедрение зависимостей!

РЕДАКТИРОВАТЬ

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


2

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

Слабая связь = IoC См. Это для более легкого объяснения.


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

2

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


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

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

Тесная связь Тесно связанный объект - это объект, который должен знать о других объектах и ​​обычно сильно зависит от интерфейсов друг друга. Изменение одного объекта в тесно связанном приложении часто требует изменения ряда других объектов. В небольших приложениях мы можем легко идентифицировать изменения и меньше шансов что-либо пропустить. Но в больших приложениях эти взаимозависимости не всегда известны каждому программисту, и есть вероятность пропустить изменения. Пример:

    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, чтобы получить свое состояние, в котором применяются правила. Если класс A будет изменен внутри, класс B не сломается, поскольку он использует только класс A в качестве способа связи.

Output
getA() method
aObject value is: 0
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.