C ++의 접근 자 메서드 (getter 및 setter)에 대한 규칙
C ++의 접근 자 메서드에 대한 몇 가지 질문이 SO에서 요청되었지만 문제에 대한 호기심을 충족시킬 수있는 사람은 없습니다.
Stroustrup과 다른 유명한 프로그래머처럼 접근자가 많은 클래스를 나쁜 OO의 징후로 간주하기 때문에 가능한 한 접근자를 피하려고합니다. C ++에서는 대부분의 경우 클래스에 더 많은 책임을 추가하거나이를 피하기 위해 friend 키워드를 사용할 수 있습니다. 그러나 어떤 경우에는 특정 클래스 구성원에 대한 액세스 권한이 정말로 필요합니다.
몇 가지 가능성이 있습니다.
1. 접근자를 전혀 사용하지 마십시오.
각 멤버 변수를 공개 할 수 있습니다. 이것은 Java에서는 실행되지 않지만 C ++ 커뮤니티에서는 괜찮은 것 같습니다. 그러나 객체에 대한 명시 적 복사 또는 읽기 전용 (const) 참조가 반환되어야하는 경우에 대해 약간 걱정됩니다. 과장된 것입니까?
2. 자바 스타일의 get / set 메소드 사용
Java에서 온 것인지 확실하지 않지만 이것은 의미합니다.
int getAmount(); // Returns the amount
void setAmount(int amount); // Sets the amount
3. 객관적인 C 스타일 get / set 메서드 사용
이것은 약간 이상하지만 점점 더 일반적입니다.
int amount(); // Returns the amount
void amount(int amount); // Sets the amount
작동하려면 멤버 변수에 대해 다른 이름을 찾아야합니다. 어떤 사람들은 밑줄을 추가하고 다른 사람들은 "m_"앞에 추가합니다. 나도 좋아하지 않습니다.
어떤 스타일을 사용하고 왜 사용합니까?
유지 관리 관점에서 4 백만 줄의 C ++ 코드 (단 하나의 프로젝트에 불과 함)가있는 내 관점에서 나는 다음과 같이 말할 것입니다.
멤버가 불변
const
이거나 (즉 ) 종속성이없는 단순 (멤버 X 및 Y가있는 포인트 클래스) 인 경우에는 getter / setter를 사용하지 않는 것이 좋습니다 .회원
private
만 있으면 게터 / 세터를 건너 뛰어도 괜찮습니다. 또한 내부 pimpl 클래스의 구성원을private
.cpp 단위가 작은 것처럼 계산합니다.멤버가
public
또는protected
(protected
만큼 나쁘고public
)const
비-단순하지 않거나 종속성이있는 경우 getter / setter를 사용합니다.
유지 보수 담당자로서 게터 / 세터를 갖고 싶어하는 주된 이유는 브레이크 포인트 / 로깅 / 다른 것을 넣을 장소가 있기 때문입니다.
검색 가능성이 더 높기 때문에 대안 2 스타일을 선호합니다 (유지 관리 가능한 코드 작성의 핵심 구성 요소).
2) 귀하의 의도를 가장 명확하게하기 때문에 최고의 IMO입니다. set_amount(10)
은보다 의미가 amount(10)
있으며 좋은 부작용으로 amount
.
캡슐화가 없기 때문에 공용 변수는 일반적 으로 나쁜 생각입니다. 변수가 업데이트 될 때 캐시를 업데이트하거나 창을 새로 고쳐야한다고 가정합니까? 변수가 공개이면 너무 나쁩니다. 설정된 메서드가있는 경우 여기에 추가 할 수 있습니다.
나는이 스타일을 사용하지 않는다. 클래스 디자인의 미래를 제한 할 수 있기 때문에 명시 적 geter 또는 setter는 좋은 컴파일러와 마찬가지로 효율적입니다.
물론 실제로 인라인 명시 적 getter 또는 setter는 클래스 구현에 대한 기본 종속성만큼이나 많이 생성합니다. 의미 론적 종속성을 줄입니다. 변경하면 여전히 모든 것을 다시 컴파일해야합니다.
접근 자 메서드를 사용할 때의 기본 스타일입니다.
이 스타일은 나에게 너무 영리 해 보인다. 드물게 사용하지만 접근자가 가능한 한 변수처럼 느껴지기를 원하는 경우에만 사용합니다.
나는 그들이 모두 정상으로 초기화되었는지 확인하기 위해 생성자를 가진 간단한 변수 가방에 대한 경우가 있다고 생각합니다. 이 작업을 수행 할 때 간단히 a로 struct
만들고 모두 공개합니다.
pure
데이터 를 표현하고 싶다면 좋은 스타일 입니다.나는 그것을 좋아하지 않는다 :)
get_/set_
우리가 C ++에서 그것들을 오버로드 할 수있을 때 정말로 불필요 하기 때문 이다.STL과 같은이 스타일을 사용
std::streamString::str
하고std::ios_base::flags
그것을 피해야하는 경우를 제외하고! 언제? 다른 유형의 이름을 가진 메소드의 이름이 충돌 후 때get_/set_
스타일과 같은 사용std::string::get_allocator
의 때문에std::allocator
.
일반적으로 시스템의 너무 많은 엔티티에서 너무 많은 게터와 세터를 사용하는 것은 좋지 않다고 생각합니다. 이는 잘못된 설계 또는 잘못된 캡슐화의 표시 일뿐입니다.
그러나 그러한 디자인을 리팩토링해야하고 소스 코드를 사용할 수있는 경우 방문자 디자인 패턴을 사용하는 것이 좋습니다. 그 이유는:
ㅏ. 클래스에게 개인 상태에 대한 액세스를 허용 할 사람을 결정할 수있는 기회를 제공합니다.
비. 개인 상태에 관심이있는 각 엔터티에 허용 할 액세스 권한을 클래스에 결정할 수있는 기회를 제공합니다.
씨. 명확한 클래스 인터페이스를 통해 이러한 외부 액세스를 명확하게 문서화합니다.
기본 아이디어는 다음과 같습니다.
a) 가능하면 재 설계하십시오.
b) 다음과 같은 리팩터링
클래스 상태에 대한 모든 액세스는 잘 알려진 개별 인터페이스 를 통해 이루어집니다.
예를 들어 외부 엔티티 GOOD의 모든 액세스가 허용되어야하고, 외부 엔티티 BAD의 모든 액세스 가 허용되지 않아야하며, 외부 엔티티 OK 가 가져 오도록 허용되어야하는 등 각 인터페이스에 대해 일종의해야 할 일과하지 말아야 할 일을 구성 할 수 있어야합니다. 설정되지 않음 (예 :)
나는 접근자를 사용에서 제외하지 않을 것입니다. 일부 POD 구조는 가능하지만 좋은 것으로 생각합니다 (일부 접근 자도 추가 논리를 가질 수 있음).
코드에서 일관성이 있다면 명명 규칙은 실제로 중요하지 않습니다. 여러 타사 라이브러리를 사용하는 경우 어쨌든 다른 명명 규칙을 사용할 수 있습니다. 그래서 그것은 맛의 문제입니다.
의미있는 데이터를 참조하기 위해 정수 유형 대신 클래스의 이상화를 보았습니다.
아래와 같은 것은 일반적으로 C ++ 속성을 잘 사용하지 않습니다.
struct particle {
float mass;
float acceleration;
float velocity;
} p;
왜? p.mass * p.acceleration의 결과는 예상대로 강제가 아닌 부동 소수점이기 때문입니다.
목적을 지정하기위한 클래스의 정의 ( 앞에서 언급 한 금액 과 같은 값이더라도 )가 더 합리적이며 다음과 같은 작업을 수행 할 수 있습니다.
struct amount
{
int value;
amount() : value( 0 ) {}
amount( int value0 ) : value( value0 ) {}
operator int()& { return value; }
operator int()const& { return value; }
amount& operator = ( int const newvalue )
{
value = newvalue;
return *this;
}
};
int 연산자에 의해 암시 적으로 amount 값에 액세스 할 수 있습니다. 더욱이:
struct wage
{
amount balance;
operator amount()& { return balance; }
operator amount()const& { return balance; }
wage& operator = ( amount const& newbalance )
{
balance = newbalance;
return *this;
}
};
Getter / Setter 사용 :
void wage_test()
{
wage worker;
(amount&)worker = 100; // if you like this, can remove = operator
worker = amount(105); // an alternative if the first one is too weird
int value = (amount)worker; // getting amount is more clear
}
이것은 다른 접근 방식이며 좋거나 나쁘다는 것을 의미하지는 않지만 다릅니다.
가장 간결 해 보이는 추가 가능성에 대해 말씀 드리겠습니다.
읽고 수정해야 함
해당 변수를 public으로 선언하기 만하면됩니다.
class Worker {
public:
int wage = 5000;
}
worker.wage = 8000;
cout << worker.wage << endl;
읽기만 필요
class Worker {
int _wage = 5000;
public:
inline int wage() {
return _wage;
}
}
worker.wage = 8000; // error !!
cout << worker.wage() << endl;
이 접근 방식의 단점은 액세스 패턴을 변경하려는 경우 모든 호출 코드를 변경 (즉, 괄호 추가)해야한다는 것입니다.
An additional possibility could be :
int& amount();
I'm not sure I would recommend it, but it has the advantage that the unusual notation can refrain users to modify data.
str.length() = 5; // Ok string is a very bad example :)
Sometimes it is maybe just the good choice to make:
image(point) = 255;
Another possibility again, use functional notation to modify the object.
edit::change_amount(obj, val)
This way dangerous/editing function can be pulled away in a separate namespace with it's own documentation. This one seems to come naturally with generic programming.
'Nice programing' 카테고리의 다른 글
> 대> = 버블 정렬로 인해 상당한 성능 차이 발생 (0) | 2020.10.27 |
---|---|
.gitignore의 git 하위 모듈을 무시하거나 저장소에 커밋합니까? (0) | 2020.10.27 |
iOS Private API 문서 (0) | 2020.10.27 |
템플릿 매개 변수 팩을 확장하지 않고 "저장"할 수 있습니까? (0) | 2020.10.27 |
Spark 작업이 org.apache.spark.shuffle.MetadataFetchFailedException으로 실패하는 이유 : 추측 모드에서 셔플 0의 출력 위치가 누락 되었습니까? (0) | 2020.10.27 |