답변:
긴밀한 결합은 클래스 그룹이 서로 의존성이 높은 경우입니다.
이 시나리오는 수업이 너무 많은 책임을 맡거나 자신의 수업이 아닌 많은 수업에 대해 하나의 관심사가 퍼져있을 때 발생합니다.
느슨한 커플 링은 단일 책임과 우려의 분리를 촉진하는 디자인을 통해 달성됩니다.
느슨하게 결합 된 클래스는 다른 (콘크리트) 클래스와 독립적으로 소비 및 테스트 할 수 있습니다.
인터페이스는 디커플링에 사용할 수있는 강력한 도구입니다. 클래스는 다른 구체적인 클래스가 아닌 인터페이스를 통해 통신 할 수 있으며 인터페이스를 구현하여 모든 클래스가 해당 통신의 다른 쪽 끝에있을 수 있습니다.
타이트한 커플 링의 예 :
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)
{
}
}
모자는 몸에 "느슨하게 결합되어있다". 즉 사람 / 신체를 변경하지 않고도 모자를 쉽게 벗을 수 있습니다. 그렇게하면 "느슨한 커플 링"이됩니다. 자세한 내용은 아래를 참조하십시오.
당신의 피부를 생각하십시오. 그것은 당신의 몸에 붙어 있습니다. 장갑처럼 맞습니다. 그러나 피부색을 흰색에서 녹색으로 바꾸려면 어떻게해야합니까? 피부를 벗겨 내고 염색 한 다음 다시 붙이는 것이 얼마나 고통 스러운지 상상할 수 있습니까? 피부와 몸이 밀접하게 결합되어 있기 때문에 피부를 바꾸는 것은 어렵습니다. 당신은 쉽게 변경할 수 없습니다. 이것을 가능하게하려면 인간을 근본적으로 재 설계해야합니다.
신은 좋은 객체 지향 프로그래머가 아니었다.
이제 아침에 옷을 입는 것을 생각하십시오. 당신은 파란색을 좋아하지 않습니까? 문제 없습니다 : 대신 빨간 셔츠를 입을 수 있습니다. 셔츠가 실제로 피부와 같은 방식으로 신체에 연결되어 있지 않기 때문에 쉽고 간편하게이 작업을 수행 할 수 있습니다. 셔츠는 몸이 어떤지 잘 모르거나 신경 쓰지 않습니다 . 다시 말해, 실제로 몸을 바꾸지 않고도 옷을 갈아 입을 수 있습니다.
그것은 기본 개념입니다.
소프트웨어가 항상 바뀌기 때문에 중요합니다. 일반적으로 코드를 변경하지 않고 코드를 쉽게 수정할 수 있기를 원합니다. 나는 그것이 옥시 모론처럼 들리지만, 나와 함께 견뎌주십시오.
CSV / JSON / DB 예 : 누군가가 JSON 등이 아닌 CSV 파일로 출력을 원하거나 MySQL에서 PostGreSQL로 전환하려는 경우 코드를 다시 작성하지 않고도 이러한 변경을 매우 쉽게 수행 할 수 있어야합니다. 다시 말해 전체 클래스 등입니다. 즉, 응용 프로그램을 특정 데이터베이스 구현 (예 : Mysql) 또는 특정 출력 (예 : CSV 파일)과 밀접하게 연결하고 싶지 않습니다. 소프트웨어에서 불가피하게 변경이 이루어질 것이기 때문입니다. 그들이 올 때 코드의 일부가 느슨하게 결합되어 있으면 훨씬 쉽습니다.
자동차 부품 예 : 누군가가 자동차 를 검은 색으로 원할 경우 전체 자동차를 재 설계하지 않아도됩니다. 자동차와 그 예비 부품은 느슨하게 결합 된 아키텍처의 완벽한 예입니다. 엔진을 더 나은 엔진으로 교체하려면 너무 많은 노력을 들이지 않고 간단히 엔진을 제거하고 더 나은 엔진으로 교체 할 수 있어야합니다. 자동차가 Rolls Royce 1234 엔진에서만 작동하고 다른 엔진은 작동하지 않는 경우 자동차는 해당 엔진과 밀접하게 연결됩니다 (Rolls Royce 1234). 자동차 디자인을 변경하여 어떤 자동차와 도 작동하도록하는 것이 좋습니다엔진의 구성 요소와 좀 더 느슨하게 연결됩니다. 엔진이 전혀 필요없이 자동차가 작동 할 수 있다면 더욱 좋습니다! 어느 정도의 커플 링이 발생할 수 있지만 최대한 최소화하기 위해 노력해야합니다. 왜? 요구 사항이 변경 될 때에도 여전히 양질의 소프트웨어를 매우 신속하게 제공 할 수 있어야하고 느슨한 결합을 통해 이러한 목표를 달성 할 수 있습니다.
간단히 말해서 느슨한 결합으로 코드를 쉽게 변경할 수 있습니다. 위의 답변은이 시점에서 읽을 가치가있는 코드를 제공합니다.
Re : @TimoHuovinen 의견-느슨한 결합의 개념은 다형성의 개념과 밀접한 관련이 있습니다. 셔츠 / 자동차 부품의 기본 비유를 파악하면 다형성을 이해할 준비가됩니다. 이 시점에서 가장 좋은 방법은이 스레드의 다른 답변에서 예상 가능한 동료가 제공 한 코드 샘플을 읽는 것입니다. 더 이상 말하면 너무 많은 정보가 과부하 될 수 있습니다.
그림 기여 .
객체 지향 디자인에서 커플 링 양은 한 클래스의 디자인이 다른 클래스의 디자인에 얼마나 의존 하는지를 나타냅니다. 다시 말해, 클래스 A의 변경이 클래스 B의 변경과 관련된 빈도는 얼마나됩니까? 긴밀한 결합은 두 클래스가 종종 함께 변경됨을 의미하고 느슨한 결합은 대부분 독립적입니다. 일반적으로 테스트 및 유지 관리가 더 쉽기 때문에 느슨한 커플 링이 권장됩니다.
Martin Fowler (PDF)의이 문서가 도움 이 될 수 있습니다.
일반적으로 Tight Coupling은 좋지 않지만 대부분의 경우 코드의 유연성과 재사용 성이 떨어지기 때문에 변경이 훨씬 어려워지고 테스트 가능성 등을 방해합니다.
Tightly Coupled Object는 서로에 대해 꽤 알아야 할 객체이며 일반적으로 서로 인터페이스에 크게 의존합니다. 밀접하게 결합 된 응용 프로그램에서 하나의 개체를 변경하려면 종종 여러 다른 개체를 변경해야합니다. 작은 응용 프로그램에서는 변경 사항을 쉽게 식별 할 수 있으며 누락 될 가능성이 적습니다. 그러나 대규모 응용 프로그램에서 이러한 상호 종속성이 모든 프로그래머에게 항상 알려진 것은 아니며 변경 사항을 놓칠 가능성이 있습니다. 그러나 느슨하게 연결된 각 개체 집합은 다른 개체에 종속되지 않습니다.
간단히 말해서, 느슨한 결합은 한 구성 요소의 변경으로 인해 다른 구성 요소의 변경이 필요할 위험을 줄이기 위해 시스템 구성 요소 간의 상호 의존성을 줄이려는 설계 목표입니다. 느슨한 커플 링은 시스템의 유연성을 높이고 유지 관리가 용이하며 전체 프레임 워크를보다 안정적으로 만들기위한 훨씬 일반적인 개념입니다.
커플 링은 한 요소가 다른 요소에 대해 가지고있는 직접적인 지식의 정도를 나타냅니다. 예를 들어 A와 B를 말할 수 있습니다. A 만 동작을 변경할 때만 B 만 동작을 변경합니다. 느슨하게 결합 된 시스템은 쉽게 정의 가능한 요소로 나눌 수 있습니다.
내 블로그 게시물 에서 커플 링에 대한 발췌 :
타이트 커플 링 이란? :-
위에서 정의한 것처럼 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()
방법은 카트의 현재 항목에 대한 전체 금액을 제공합니다. 이 장바구니 시스템에 할인 기능을 추가하려면 우리는 모든 클래스에서 매우 밀접하게 결합되어 있기 때문에 모든 클래스에서 변경해야하기 때문에 위의 코드에서 수행하기가 매우 어렵습니다.
느슨한 결합은 두 구성 요소 간의 종속성 정도가 매우 낮음을 의미합니다.
예 : GSM SIM
긴밀한 결합은 두 구성 요소 간의 종속성 정도가 매우 높다는 것을 의미합니다.
예 : CDMA 모바일
긴밀한 커플 링 은 한 클래스가 다른 클래스에 종속됨을 의미합니다.
느슨한 연결 은 하나의 클래스가 클래스가 아닌 인터페이스에 종속됨을 의미합니다.
밀접한 결합 에서는 메소드에 선언 된 하드 코딩 된 종속성이 있습니다. 느슨한 결합
에서는 런타임에 하드 코딩 된 것이 아니라 외부에서 종속성을 전달해야합니다. 느슨한 커플 시스템은 클래스와의 종속성을 줄이기 위해 인터페이스를 사용합니다.
예를 들어 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();
}
}
라이브러리를 통해 의존성 주입을 제공하는 특정 도구가 있습니다 . 예를 들어 .net에는 ninject Library가 있습니다.
Java로 더 나아가면 spring 이이 기능을 제공합니다.
코드에 인터페이스를 도입하여 느슨하게 연결된 객체를 만들 수 있습니다.
코드에서 작성하고 있다고 말하십시오.
Myclass m = new Myclass();
이제 당신의 방법에있는이 진술은 당신이 이것에 의존한다고 myclass
단단히 결합되어 있습니다. 이제 생성자 주입 또는 속성 주입 및 인스턴스화 객체를 제공하면 느슨하게 결합됩니다.
유추를 사용하여 여기에 좋은 대답이 많이 있지만 직장의 친구가 여기에 언급 된 모든 것보다 더 좋아하는 예를 들었습니다 ... 눈과 안경!
꽉 커플 링
긴밀한 결합이 눈이 될 것입니다. 내 시력을 고치려면 안구 이식을받는 데 비용이 많이 들고 상당한 위험이 따릅니다. 그러나 디자이너 (인간이되는 것)가 더 나은 길을 찾았다면 어떨까요? 본체에 느슨하게 결합 된 기능을 추가하여 쉽게 변경할 수 있습니다! (예. 안경)
느슨한 결합
내 시력을 훼손하지 않고도 안경을 쉽게 교체 할 수 있습니다. 나는 안경을 벗을 수 있고 나의 비전은 이전의 모습 일 것이다. 다른 안경을 사용하면 위험이 적고 유지 관리가 쉬운 눈으로 세상을 보는 방식이 바뀝니다.
요약
다음에 누군가가 "내 코드가 밀접하게 연결되어 있는지 누가 신경 쓰나요?" 답은 변화를위한 노력, 유지하려는 노력 및 변화의 위험에 관한 것입니다.
그래서 이것은 C #에서 어떻게 이루어 집니까? 인터페이스와 의존성 주입!
편집하다
이것은 데코레이터 패턴의 좋은 예입니다. 눈은 인터페이스 요구 사항을 충족하지만 다른 기능 (예 : 선글라스, 독서 용 안경, 보석상 용 돋보기 등)을 제공하여 장식하는 클래스입니다.
그것은 느슨하게 결합되어 너무 낮고 단단히 결합되어 너무 높은 다른 클래스에 대한 클래스 종속성 비율 에 관한 것입니다. 서비스 지향 아키텍처 에서 명확하게하기 위해 , 서비스는 서로 의존하는 클래스가 모 놀리 식에 대해 서로 느슨하게 연결되어 있습니다.
객체의 생성 / 존재가 조정될 수없는 다른 객체에 의존한다면, 그 긴밀한 결합입니다. 그리고 의존성을 조정할 수 있다면 느슨한 결합입니다. 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 인터페이스를 사용하는 것은 적절한 desing 접근법이 아닙니다. Java에서 인터페이스는 디커플링 동작 / 장점을 본질적으로 제공하는 계약의 역할을합니다.
수락 된 답변에 대한 Bill Rosmus의 의견에는 좋은 설명이 있습니다.
긴밀한 결합은 클래스와 객체가 서로 종속됨을 의미합니다. 일반적으로 타이트 커플 링은 일반적으로 코드의 유연성과 재사용 성을 감소시키기 때문에 좋지 않습니다. 느슨한 커플 링은 다른 클래스를 직접 사용하는 클래스의 종속성을 줄이는 것을 의미합니다.
긴밀한 결합 긴밀하게 결합 된 오브젝트는 다른 오브젝트에 대해 알아야하는 오브젝트이며 보통 서로의 인터페이스에 크게 의존합니다. 밀접하게 연결된 응용 프로그램에서 하나의 개체를 변경하려면 종종 다른 여러 개체를 변경해야합니다. 소규모 응용 프로그램에서는 변경 사항을 쉽게 식별 할 수 있으며 누락 된 부분이 없습니다. 그러나 대규모 응용 프로그램에서 이러한 상호 종속성이 모든 프로그래머에게 항상 알려진 것은 아니며 변경 사항을 간과 할 가능성이 있습니다. 예:
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가 적용되는 상태를 얻기 위해 클래스 B가 클래스 A를 거쳐야하므로 권장됩니다. 클래스 A가 내부적으로 변경되면 클래스 B는 통신 방법으로 클래스 A 만 사용하므로 중단되지 않습니다.
Output
getA() method
aObject value is: 0