'높은 응집력'의 의미는 무엇입니까?


28

저는 최근 소프트웨어 개발 회사에 인턴으로 입사 한 학생입니다. 대학으로 돌아가 교수님 중 한 명은 "낮은 커플 링과 높은 응집력"을 달성하기 위해 노력해야한다고 말했습니다.

나는 낮은 커플 링의 의미를 이해합니다. 한 구성 요소를 변경해도 다른 구성 요소의 코드가 손상되지 않도록 별도의 구성 요소 코드를 별도로 유지해야합니다.

그러나 높은 응집력의 의미는 무엇입니까? 동일한 구성 요소의 다양한 부분을 서로 잘 통합한다는 의미라면 그것이 어떻게 유리한지 이해할 수 없습니다.

높은 응집력이란 무엇입니까? 장점을 이해하기 위해 예를 설명 할 수 있습니까?



1
Wikipedia 기사가 귀하의 질문에 충분히 답변하지 않습니까? en.wikipedia.org/wiki/Cohesion_(computer_science)
Eoin Carroll

에서 이것에 대해 좋은 기사가있다 : msdn.microsoft.com/en-us/magazine/cc947917.aspx은
NoChance

1
@EoinCarroll : 불행히도 현재의 위키 백과 기사는 새로운 프로그래머가 사용할 수있는 구체적인 예 를 제공하지 않습니다 . 이론은 모두 훌륭하지만, 응집력이 낮은 실수를 다룰 때까지는 실제로 적용되지 않습니다. 높은 응집력은 중요한 이유와 달성 방법 을 완전히 이해하기 위해 몇 년 동안 프로그래밍을해온 주제 중 하나입니다 .
Spoike

Clean Code를 읽을 때까지 Cohesion을 실제로 이해하지 못했습니다. 당신도 그래야합니다.
Sebastian Redl

답변:


25

OO와 관련하여 응집력을 보는 한 가지 방법은 클래스의 메소드가 개인 속성을 사용하는 경우입니다. 이 답변 here 에서 gnat 지적한 LCOM4 (Lhe of Cohesive Methods)와 같은 메트릭을 사용하면 리팩토링 할 수있는 클래스를 식별 할 수 있습니다. 메소드 나 클래스를보다 응집력있게 리팩토링하려는 이유는 다른 사람이 코드 디자인을 더 쉽게 사용할 수 있기 때문 입니다. 날 믿어; 이러한 문제를 해결하면 대부분의 기술 리드 및 유지 보수 프로그래머가 귀하를 사랑합니다.

Sonar 와 같은 빌드 프로세스에서 도구를 사용 하여 코드 기반의 낮은 응집력을 식별 할 수 있습니다 . "응집성" 이 낮은 방법을 생각할 수있는 몇 가지 매우 일반적인 경우가 있습니다 .

사례 1 : 방법은 클래스와 전혀 관련이 없습니다.

다음 예제를 고려하십시오.

public class Food {
   private int _foodValue = 10;

   public void Eat() {
     _foodValue -= 1;
   }

   public void Replenish() {
     _foodValue += 1;
   }

   public void Discharge() {
     Console.WriteLine("Nnngghhh!");
   }
}

방법 중 하나는 Discharge()클래스의 개인 구성원과 접촉하지 않기 때문에 응집력이 부족합니다. 이 경우 개인 멤버는 하나뿐입니다 _foodValue. 클래스 내부와 관련이 없다면 실제로 거기에 속합니까? 이 메소드는 예를 들어 이름을 지정할 수있는 다른 클래스로 이동할 수 있습니다 FoodDischarger.

// Non-cohesive function extracted to another class, which can
// be potentially reused in other contexts
public FoodDischarger {
  public void Discharge() {
    Console.WriteLine("Nnngghhh!");
  }
}

함수는 일류 객체이기 때문에 Javascript 에서이 작업을 수행하면 배출이 무료 기능이 될 수 있습니다.

function Food() {
    this._foodValue = 10;
}
Food.prototype.eat = function() {
    this._foodValue -= 1;
};
Food.prototype.replenish = function() {
    this._foodValue += 1;
};

// This
Food.prototype.discharge = function() {
    console.log('Nnngghhh!');
};
// can easily be refactored to:
var discharge = function() {
    console.log('Nnngghhh!');
};
// making it easily reusable without creating a class

사례 2 : 유틸리티 클래스

이것은 실제로 응집력을 잃는 일반적인 경우입니다. 모두 유틸리티 클래스를 좋아 하지만, 이는 일반적으로 설계 결함을 나타내며 대부분의 경우 유틸리티 클래스와 관련된 높은 종속성 때문에 코드베이스를 유지 관리하기가 더 까다로워집니다. 다음 클래스를 고려하십시오.

public class Food {
    public int FoodValue { get; set; }
}

public static class FoodHelper {

    public static void EatFood(Food food) {
        food.FoodValue -= 1;
    }

    public static void ReplenishFood(Food food) {
        food.FoodValue += 1;
    }

}

여기에서 유틸리티 클래스가 클래스의 속성에 액세스해야 함을 알 수 있습니다 Food. 이 경우 유틸리티 클래스의 메소드는 작업을 수행하기 위해 외부 자원이 필요하기 때문에 응집력이 없습니다. 이 경우 작업하는 클래스에 메소드를 갖는 것이 더 좋지 않습니까 (첫 번째 경우와 유사)?

사례 2b : 유틸리티 클래스의 숨겨진 객체

실현되지 않은 도메인 객체가있는 유틸리티 클래스의 또 다른 경우가 있습니다. 문자열 조작을 프로그래밍 할 때 프로그래머가 가지고있는 첫 번째 반응은 유틸리티 클래스를 작성하는 것입니다. 여기에 몇 가지 일반적인 문자열 표현을 확인하는 것과 같습니다.

public static class StringUtils {

  public static bool ValidateZipCode(string zipcode) {
    // validation logic
  }

  public static bool ValidatePhoneNumber(string phoneNumber) {
    // validation logic
  }

}

여기서 가장 잘 모르는 것은 우편 번호, 전화 번호 또는 기타 문자열 반복이 객체 자체가 될 수 있다는 것입니다.

public class ZipCode {
    private string _zipCode;
    public bool Validates() {
      // validation logic for _zipCode
    }
}

public class PhoneNumber {
    private string _phoneNumber;
    public bool Validates() {
      // validation logic for _phoneNumber
    }
}

이 코드 를 @codemonkeyism의해 직접 다루지 말아야한다는 개념은 @codemonkeyism의해 자세히 설명되어 있지만 프로그래머가 로직을 유틸리티 클래스에 넣어서 문자열을 사용하는 방식 때문에 응집력과 밀접한 관련이 있습니다.


ORM이 사용자 정의 ZipCode 및 PhoneNumber 클래스를 올바르게 처리 할 수만 있다면 다음과 같습니다. |
Pete


@Pete 문자열에서 정의 된 형식 (ZipCode, PhoneNumber)으로 변환 연산자를 제공하면 ORM에서 처리합니다. msdn.microsoft.com/en-us/library/85w54y0a.aspx
Marcus

9

높은 응집력은 유사하고 관련된 것들을 함께 유지하고 콘텐츠, 기능, 이유 또는 목표 를 공유하는 부품을 결합하거나 융합하는 것을 의미합니다 . 다시 말해, 낮은 응집력은 예를 들어 " 지점 " 이 아닌 여러 목적을 수행하는 기능 / 클래스 / 코드 엔티티를 의미 할 수있다 . 운반 아이디어 중 하나는 한 가지 일을하고 잘하는 것 입니다. 다른 곳에서는 여러 곳에서 유사한 기능을 복제하지 않는다는 명백한 사실이 포함될 수 있습니다. 이것은 또한 코드베이스의 지역성 을 향상 시키며 특정 종류의 것들이 흩어져있는 것이 아니라 특정 장소 (파일, 클래스, 함수 집합 등)에서 발견됩니다.

예를 들어, 2 가지 또는 3 가지 목적을 제공하는 클래스를 고려하십시오. 리소스 (예 : 파일)를로드 / 저장 한 다음 컨텐츠를 분석 및 표시합니다. 이러한 클래스는 전혀 관련이없는 적어도 두 개의 개별 작업 (파일 I / O, 분석 및 표시)을 관리하기 때문에 응집력 이 습니다 . 응집력이 높은 설계에서는 리소스를로드 및 저장하고 분석 한 다음 표시하기 위해 고유 한 클래스를 사용할 수 있습니다.

반면, 낮은 커플 링은 서로 구별되는 것을 분리하여 가능한 적은 상호 작용을하여 복잡성을 줄이고 설계를 단순화하는 것을 목표로합니다.


7

주어진 객체의 부분이 객체의 기능과 밀접한 관련이 있음을 의미합니다. 이는 기능 또는 책임 측면에서 객체 내에 폐기물이 거의 없거나 전혀 없음을 의미합니다. 이것은 문제의 대상이 무엇을 사용해야하는지에 대한 이해를 향상시킬 수 있습니다.


객체보다 더 높은 수준에도 적용되지 않습니까? 예를 들어 네임 스페이스에서 작업과 관련된 객체 / 기능을 그룹화합니까?
stijn
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.