주어진 클래스 정의에서 나는 알파벳순, 가장 일반적인 사용법에 따른 시간순, 가시성에 따라 알파벳순, 게터와 세터에 알파벳순으로 그룹화되는 등 다양한 방법으로 순서가 정의 된 것을 보았습니다. 나는 모든 것을 입력 한 다음 전체 수업을 다 마치면 순서를 바꾸는 경향이 있습니다. 그 메모에 세 가지 질문이 있습니다.
- 주문이 중요합니까?
- "최상의"주문이 있습니까?
- 나는 그렇지 않다고 추측하고 있으므로 다른 주문 전략의 장단점은 무엇입니까?
주어진 클래스 정의에서 나는 알파벳순, 가장 일반적인 사용법에 따른 시간순, 가시성에 따라 알파벳순, 게터와 세터에 알파벳순으로 그룹화되는 등 다양한 방법으로 순서가 정의 된 것을 보았습니다. 나는 모든 것을 입력 한 다음 전체 수업을 다 마치면 순서를 바꾸는 경향이 있습니다. 그 메모에 세 가지 질문이 있습니다.
답변:
일부 프로그래밍 언어에서는 선언 된 후에야 물건을 사용할 수 없으므로 순서가 중요합니다. 그러나 대부분의 언어는 컴파일러에 중요하지 않습니다. 그럼, 당신은 인간에게 중요하게 남아 있습니다.
내가 가장 좋아하는 Martin Fowler 인용문은 다음과 같습니다. Any fool can write code that a computer can understand. Good programmers write code that humans can understand.
클래스의 순서는 인간이 이해하기 쉬운 요소에 달려 있어야한다고 말합니다.
나는 개인적으로 Bob Martin이 그의 Clean Code
책 에서 제공하는 강압 치료를 선호합니다 . 클래스 상단의 멤버 변수, 생성자 및 기타 모든 메서드 그리고 모든 클래스를 임의로 공개 한 다음 보호하는 대신 클래스 내에서 사용되는 방식과 밀접하게 메소드를 주문합니다. 그는 그것을 "수직 거리"나 그와 비슷한 것을 최소화하는 것으로 부릅니다 (현재 책을 가지고 있지 않습니다).
편집하다:
"수직 거리"의 기본 개념은 사람들이 소스 코드를 이해하기 위해 모든 소스 코드를 뛰어 넘지 않도록하는 것입니다. 사물이 관련되어 있으면 서로 더 가까워 야합니다. 관련이없는 것들이 더 멀어 질 수 있습니다.
Clean Code (위대한 책, btw) 5 장 에서는 Martin이 주문 코드를 제안하는 방법에 대해 자세히 설명합니다. 그는 코드를 읽는 것은 신문 기사를 읽는 것과 같은 방식으로 작동해야한다고 제안합니다. 높은 수준의 세부 정보가 맨 처음에 나오고 읽을 때 더 자세하게 정보를 얻을 수 있습니다. 그는 "한 함수가 다른 함수를 호출하면 수직으로 가까워 야하며 가능하면 호출자가 수신자 위에 있어야합니다."라고 말합니다. 또한 관련 개념이 서로 비슷해야합니다.
다음은 여러 가지면에서 좋지 않은 (OO 디자인이 나쁘고 double
돈을 절대로 사용하지 않는) 고안된 예입니다 .
public class Employee {
...
public String getEmployeeId() { return employeeId; }
public String getFirstName() { return firstName; }
public String getLastName() { return lastName; }
public double calculatePaycheck() {
double pay = getSalary() / PAY_PERIODS_PER_YEAR;
if (isEligibleForBonus()) {
pay += calculateBonus();
}
return pay;
}
private double getSalary() { ... }
private boolean isEligibleForBonus() {
return (isFullTimeEmployee() && didCompleteBonusObjectives());
}
public boolean isFullTimeEmployee() { ... }
private boolean didCompleteBonusObjectives() { ... }
private double calculateBonus() { ... }
}
메소드는 그것들을 호출하는 메소드에 가깝게 정렬되어 위에서 아래로 내려갑니다. 모든 private
방법을 아래에 적어 놓았다면 public
프로그램 흐름을 따르기 위해 더 많은 점프를해야합니다.
getFirstName
과 getLastName
개념적으로 관련이 (되고 getEmployeeId
아마 너무)가 서로 가까이 그래서. 우리는 그들에게 아래로 모두 아래로 이동할 수 있지만, 우리는보고 싶지 않을 것이다 getFirstName
상단과 getLastName
하단에.
바라건대 이것이 기본 아이디어를 제공합니다. 이런 종류의 것에 관심이 있다면을 읽는 것이 좋습니다 Clean Code
.
calculateBonus()
앞에 와야 isFullTimeEmployee()
하고 didCompleteBonusObjectives()
?
isFullTimeEmployee
하고 didCompleteBonusObjectives
사용하는 isEligibleForBonus
수직 가까운 그것을 사용하는 사람들이한다고 있도록. 그러나 잠재적으로 calculateBonus
전화를 걸어 더 가까이 갈 수 있습니다 . 불행히도 함수를 호출하는 함수가 있기 때문에 완벽한 순서가없는 문제 (예 : 여러 다른 함수가 호출 한 공유 함수)가 발생합니다. 그런 다음 최선의 판단을 내립니다. 이러한 문제를 완화하기 위해 클래스와 함수를 작게 유지하는 것이 좋습니다.
나는 일반적으로 관계 및 사용 순서에 따라 방법을 주문합니다.
네트워킹 클래스를 선택하고 모든 TCP 메소드를 그룹화 한 다음 모든 UDP 메소드를 그룹화합니다. 내부 TCP는 첫 번째로 설정 방법을 사용합니다. 어쩌면 주어진 메시지를 두 번째로 보내고 tcp 소켓을 세 번째로 닫습니다.
분명히 모든 클래스가 해당 패턴에 맞지는 않지만 이것이 일반적인 워크 플로입니다.
문제가 있고 메소드로 건너 뛰고 싶을 때 다른 방법으로 디버깅하기 위해 그 방법을 사용합니다. 어떻게 철자가 아닌지, 책임이 무엇인지 생각하고 해당 섹션으로 이동하십시오.
이 방법은 특히 코드를 함께 그룹화하여 보거나 사용하는 제 3 자에게 의미가 있으며 사용되는 순서를 따르므로 클래스로 작성할 코드는 클래스와 동일한 구조를 따릅니다.
중요합니까?
가독성을 위해 확실히.
그 외에는 실제로는 아닙니다. 특정 언어는 위에 정의 된 경우가 아니라면 메소드를 호출 할 수없는 경우에만 호출됩니다.
이상적으로는 수업이 너무 작아 중요하지 않습니다. 메소드가 12 개이고 편집기 또는 IDE가 접기를 지원하는 경우 전체 메소드 목록이 12 줄에 맞기 때문에 문제가 없습니다.
실패하면 최상위 수준의 차이는 공개 대 개인이어야합니다. 공개 메소드를 먼저 나열하십시오. 클래스가 나머지 코드베이스와 인터페이스하는 방식을 정의하기 때문에 사람들이 가장 많이 찾는 것은 다음과 같습니다.
그런 다음 각각의 내부에서 기능별로 메소드를 그룹화하는 것이 가장 합리적입니다. 한 블록의 생성자와 소멸자, 다른 블록의 getter / setter, 연산자 과부하, 정적 메소드 및 나머지 부분. C ++에서는 operator=
복사 생성자와 밀접하게 관련되어 있으며 기본 ctor, copy ctor, operator = 및 dtor의 모든 여부를 신속하게 확인할 수 있기 때문에 생성자에 가깝게 유지하고 싶습니다. 있다.
작업중인 언어에 특정 순서가 필요한 경우에만 그 외에는 주문이 귀하에게 달려 있습니다. 일관되고 이해가되는 시스템을 고르고 가능한 한 고집하십시오.
1 . 주문이 중요합니까?
작업중인 언어에 다음 예제와 같이 호출 된 위치보다 파일에서 미리 정의 된 함수가 있어야하는 경우 에만 해당합니다.
void funcA()
{
funcB();
}
void funcB()
{
//do something interesting...
}
funcB()
사용하기 전에 전화 하기 때문에 오류가 발생 합니다. PL / SQL 및 C에서도 문제라고 생각하지만 다음과 같은 전달 선언을 가질 수 있습니다.
void funcB();
void funcA()
{
funcB();
}
void funcB()
{
//do something interesting...
}
이것이 순서가 "잘못"되면 컴파일 할 수없는 곳을 생각할 수있는 유일한 상황입니다.
그렇지 않으면 언제든지 원하는대로 다시 주문할 수 있습니다. 아마도 당신을 위해 그것을 할 수있는 도구를 작성할 수도 있습니다 (당신이 그것을 찾을 수 없다면).
2. "최상의"주문이 있습니까?
언어 / 환경에 주문 요구 사항이없는 경우 "최상의"주문이 가장 적합 합니다 . 나에게는 모든 게터 / 세터를 함께 클래스의 시작 부분 (생성자 / 정적 초기화 후)과 개인 메서드, 보호 및 공용으로 함께하고 싶습니다. 각 범위 기반 그룹에서 일반적으로 존재하지 아니 내가하려고 오버로드 방법은 매개 변수의 수의 순서로 함께 유지하지만, 주문. 또한 관련 기능이있는 메소드를 함께 유지하려고하지만 때로는 범위 기반 순서를 위반해야합니다. 때로는 범위 기반 순서를 유지하려고하면 그룹별로 기능이 중단됩니다. 그리고 내 IDE는 알파벳 개요보기를 제공 할 수 있으므로 좋습니다. ;)
C #과 같은 일부 언어 는 컴파일에 영향을주지 않지만 " 함수 "로 코드를 그룹화 할 수 있지만 관련 기능을 더 쉽게 유지 한 다음 IDE로 숨기거나 표시 할 수 있습니다. 으로 MainMa 지적 이 나쁜 관행을 고려하는 사람들 일부가 있습니다. 나는 이런 식으로 사용되는 지역의 좋은 예와 나쁜 예를 보았습니다. 따라서이 방법을 사용하려면 조심하십시오.