객체 지향 프로그래밍 : getter / setter 또는 논리적 이름


12

나는 현재 내가 쓰고있는 수업에 대한 인터페이스에 대해 생각하고 있습니다. 이 클래스에는 캐릭터의 스타일, 예를 들어 캐릭터가 굵은 체, 이탤릭체, 밑줄 등이 있습니다. 값을 변경하는 메소드에 getter / setter 또는 논리적 이름을 사용해야하는지 이틀 동안 나 자신과 토론했습니다. 이 스타일. 논리적 이름을 선호하는 경향이 있지만, 효율적이지 않고 논리적이지 않은 코드를 작성한다는 의미입니다. 예를 들어 보겠습니다.

나는 수업이있어 CharacterStyles멤버 변수가 bold, italic, underline(일부 다른,하지만 난 간단하게 그들을 떠날 것이다). 가장 쉬운 방법은 당신이 할 수 있도록, 쓰기 게터 / 세터 메소드하는 것, 이러한 변수에 액세스하는 프로그램의 다른 부분을 수 있도록 styles.setBold(true)하고 styles.setItalic(false).

그러나 나는 이것을 좋아하지 않습니다. 많은 사람들이 getters / setters가 캡슐화를 깨뜨린다고 말했을뿐 아니라 (정말 나쁘지 않은가), 대부분 논리적이지 않은 것이기 때문입니다. 나는 하나의 방법 styles.format("bold", true)이나 그와 비슷한 것을 통해 캐릭터의 스타일을 기대 하지만 이러한 모든 방법을 통해서는 아닙니다.

그래도 한 가지 문제가 있습니다. C ++에서 문자열의 내용으로 객체 멤버 변수에 액세스 할 수 없으므로 모든 스타일에 대해 큰 if 문 / 스위치 컨테이너를 작성하거나 스타일을 연관 배열에 저장해야합니다 ( 지도).

가장 좋은 방법이 무엇인지 알 수 없습니다. 한 순간 나는 게터 / 세터를 써야한다고 생각하고, 다음 순간에는 다른 방향으로 몸을 기울입니다. 내 질문은 : 당신은 무엇을 할 것인가? 왜 그렇게하겠습니까?


CharacterStyles 클래스는 실제로 3 개의 부울 번들 이외의 작업을 수행합니까? 어떻게 소비됩니까?
마크 Canlas

예, CharacterStyles는 다른 CharacterStyles로부터 상속받을 수 있어야합니다. 이것은 내가 bold설정 true하고 다른 변수가 정의되지 않은 CharacterStyles가있는 경우 다른 변수의 getter 메소드는 부모 스타일의 값을 반환해야하지만 다른 속성에 저장된 속성은 getter bold가 반환해야합니다 true. 이름과 인터페이스에 표시되는 방식과 같은 다른 것들이 있습니다.
개구리

열거 형을 사용하여 다양한 스타일 옵션을 정의한 다음 switch 문을 사용할 수 있습니다. Btw, 어떻게 정의되지 않은 처리합니까?
Tyanna

@ Tyanna : 실제로 열거 형을 사용하는 것에 대해서도 생각했지만 사소한 세부 사항입니다. 정의되지 않은 값을 NULL로 설정하려고했습니다. 그게 최선의 방법이 아닙니까?
개구리

답변:


6

예, 게터 / 세터는 캡슐화를 깨뜨립니다. 기본적으로 기본 필드에 직접 액세스하는 것 사이의 추가 계층입니다. 직접 액세스 할 수도 있습니다.

이제 더 복잡한 메소드가 필드에 액세스하려면 유효하지만 필드를 노출하는 대신 클래스가 제공해야하는 메소드를 생각해야합니다. 즉. 속성을 사용하여 노출되는 Money 값을 가진 Bank 클래스 대신 Bank 객체가 제공해야하는 액세스 유형 (돈 추가, 인출, 균형 잡기)을 생각하고 대신 구현해야합니다. Money 변수의 속성은 Money 변수를 직접 노출시키는 것과 문법적으로 다릅니다.

DrDobbs에는 더 많은 기사 가 있습니다.

귀하의 문제에 대해 가능한 스타일을 열거하는 setStyle 및 clearStyle (또는 무엇이든)의 두 가지 방법이 있습니다. 그런 다음이 메소드 내의 switch 문은 관련 값을 적절한 클래스 변수에 적용합니다. 이렇게하면 나중에 (예를 들어, HTML에서 사용) 문자열로 저장하려는 경우 뭔가 다른 스타일의 내부 표현을 변경할 수 있습니다 - 무언가 클래스의 모든 사용자가 필요로 변경 될 당신이 사용하는 경우도 속성을 가져 오거나 설정합니다.

임의의 값을 원하거나 큰 if-then 문이 있거나 (몇 개가있는 경우) std :: mem_fun (또는 std :: function ) 따라서 "bold"는 값이 sts :: mem_fun 인 맵 키에 변수 굵게를 true로 설정하는 메소드에 저장됩니다 (문자열이 멤버 변수 이름과 동일하면 다음을 사용할 수도 있습니다). stringifying 매크로는 사용자가 작성해야하는 코드의 양을 줄이기 위해)


훌륭한 답변! 특히 HTML로 데이터를 저장하는 부분이 실제로이 길을 따라야하는 좋은 이유가되었습니다. 따라서 열거 형에 다른 스타일을 저장하고 styles.setStyle(BOLD, true)? 와 같은 스타일을 설정하는 것이 좋습니다 . 그 맞습니까?
개구리

예, setStyle (BOLD) 및 clearstyle (BOLD)의 두 가지 방법 만 있습니다. 두 번째 매개 변수를 잊어 버렸습니다. 그런 것을 선호하고 모든 스타일 플래그를 지우는 매개 변수를 사용하지 않도록 clearStyle을 오버로드 할 수 있습니다.
gbjbaanb

글꼴 크기와 같은 일부 유형에는 매개 변수가 필요하기 때문에 작동하지 않습니다. 그러나 여전히 답변 주셔서 감사합니다!
개구리

이것을 구현하려고 시도했지만 고려하지 않은 한 가지 문제가 있습니다. styles.getStyle(BOLD)부울 유형의 멤버 변수뿐만 아니라 정수 및 문자열 유형 (예 :)이있는 경우 어떻게 구현 합니까 styles.getStyle(FONTSIZE)? 반환 유형을 오버로드 할 수 없으므로 어떻게 프로그래밍합니까? 나는 당신이 void 포인터를 사용할 수 있다는 것을 알고 있지만, 그것은 나에게 정말 나쁜 방법처럼 들립니다. 이 작업을 수행하는 방법에 대한 힌트가 있습니까?
개구리

공용체 또는 구조체를 반환하거나 새로운 표준을 사용하면 반환 유형별로 오버로드 할 수 있습니다. 즉, 스타일을 설정하는 단일 방법을 구현하려고합니까? 여기서 style은 플래그이고 글꼴 모음이며 크기는 무엇입니까? 이 경우 추상화를 너무 많이 강제하려고 할 수 있습니다.
gbjbaanb

11

고려하지 않았을 수있는 한 가지 아이디어는 데코레이터 패턴 입니다. 객체에서 플래그를 설정 한 다음 작성중인 모든 것에 플래그를 적용하는 대신 Decorators에서 쓰기를 수행하는 클래스를 래핑하여 스타일을 적용합니다.

호출 코드는 텍스트 주위에 몇 개의 래퍼가 있는지 알 필요가 없으며 외부 객체에서 메소드를 호출하면 스택을 호출합니다.

의사 코드 예 :

class TextWriter : TextDrawingInterface {
    public:
        void WriteString(string x) {
            // write some text somewhere somehow
        }
}

class BoldDecorator : TextDrawingInterface {
    public:
        void WriteString(string x) {
            // bold application on
            m_textWriter.WriteString(x);
            // bold application off
        }

        ctor (TextDrawingInterface textWriter) {
            m_textWriter = textWriter;
        }

    private:
        TextWriter m_TextWriter;
}

등등, 각 장식 스타일에 대해. 가장 간단한 사용법으로 말할 수 있습니다.

TextDrawingInterface GetDecoratedTextWriter() {
    return new BoldDecorator(new ItalicDecorator(new TextWriter()));
}

그리고이 메소드를 호출하는 코드는 수신중인 세부 정보를 알 필요가 없습니다. WriteString 메서드를 통해 텍스트를 그릴 수있는 SOMETHING 인 한.


흠, 나는 내일을 신선한 마음으로 살펴보고 그때 당신에게 돌아올 것입니다. 답변 해주셔서 감사합니다.
개구리

저는 데코레이터 패턴을 좋아합니다. 이 패턴이 HTML과 유사하다는 사실 (핵심 조작이 입력 문자열을 태그로 묶는 것임)은이 접근법이 모든 인터페이스 사용자의 요구를 충족시킬 수 있음을 증명합니다. 명심하고 사용하기 쉬운 인터페이스에는 기술적으로 복잡한 기본 구현이있을 수 있습니다. 당신이 실제로 자신 렌더러의 텍스트를 구현하는 경우 예를 들어, 당신은 찾을 수 있습니다 TextWriter모두에게 토론의 필요 BoldDecoratorItalicDecorator(양방향) 작업을 끝내야합니다.
rwong

이것은 좋은 답변이지만 op의 질문을 다시 소개하지 않습니까? "bold applicaton on"->이 작업은 어떻게 수행됩니까? SetBold ()와 같은 setter / getter를 사용하고 있습니까? 정확히 op의 질문입니다.
stijn

1
@stijn :별로. 이러한 상황을 피하는 방법에는 여러 가지가 있습니다. 예를 들어, 배열에서 데코레이터를 추가 및 제거하고 BuildDecoratedTextWriter를 호출 할 때만 최종 항목을 장식하는 toggleStyle 메소드 (열 인수)로 빌더에서 랩핑 할 수 있습니다. 또는 rwong이 제안한대로 기본 클래스를 복잡하게 만들 수 있습니다. 상황에 따라 다르며 OP는 자신에게 가장 적합한 것을 추측하기 위해 전체 사양에 대해 충분히 구체적이지 않았습니다. 그는 일단 패턴을 얻으면 그것을 알아낼 수있을만큼 똑똑해 보입니다.
pdr

1
나는 항상 데코레이터 패턴이 장식 순서를 의미한다고 생각했습니다. 표시된 예제 코드를 고려하십시오. ItalicDecorator를 제거하는 방법은 무엇입니까? 그래도 Decorator와 같은 것이 갈 길이라고 생각합니다. 굵게, 기울임 꼴 및 밑줄 만 세 가지 스타일이 아닙니다. 얇고, 세미 볼드, 압축, 검은 색, 넓고, 기울임 꼴이있는 기울임 꼴, 작은 캡 등이 있습니다. 캐릭터에 임의로 큰 스타일 세트를 적용하는 방법이 필요할 수 있습니다.
Barry Brown

0

나는 두 번째 해결책을 향해 몸을 기울였다. 더 우아하고 유연하게 보입니다. 굵게, 기울임 꼴 및 밑줄 (개요?) 이외의 다른 유형을 상상하기는 어렵지만 멤버 변수를 사용하여 새 유형을 추가하는 것은 어렵습니다.

최신 프로젝트 중 하나에서이 방법을 사용했습니다. 여러 부울 속성을 가질 수있는 클래스가 있습니다. 속성의 수와 이름은 시간이 변경 될 수 있습니다. 사전에 저장합니다. 속성이 없으면 값이 "false"라고 가정합니다. 또한 사용 가능한 속성 이름 목록을 저장해야하지만 이는 또 다른 이야기입니다.


1
이 유형 들과는 별도로 취소 선, 글꼴 크기, 글꼴 모음, 위첨자, 아래 첨자 등을 추가 할 수 있습니다. 그러나 왜 프로젝트에서 그 방법을 선택 했습니까? 허용 된 속성 목록을 저장해야한다고 더러운 코드라고 생각하지 않습니까? 이 질문에 대한 귀하의 답변이 무엇인지 궁금합니다.
개구리

응용 프로그램이 이미 배포되었을 때 클라이언트가 일부 속성을 정의 할 수있는 상황을 처리해야했습니다. 일부 고객에게는 다른 속성이 필요하지만 다른 고객에게는 더 이상 사용되지 않습니다. 이 방법을 사용하여 양식, 저장된 데이터 세트를 사용자 정의하고 다른 문제를 해결할 수 있습니다. 더러운 코드를 생성한다고 생각하지 않습니다. 때로는 고객에게 어떤 종류의 정보가 필요할지 예측할 수 없습니다.
Andrzej Bobak

그러나 고객은 맞춤 속성을 추가 할 필요가 없습니다. 그리고이 경우에는 조금 "해킹"된 것 같습니다. 동의하지 않습니까?
개구리

동적 속성 수 문제에 직면하지 않으면 속성을 저장하기위한 유연한 공간이 필요하지 않습니다. 사실입니다 :) 나는 다른 부분에 동의하지 않습니다. 사전 / 해시 맵 등의 속성을 Stroring하는 것은 나쁜 견해가 아닙니다.
Andrzej Bobak

0

나는 당신이 문제를 지나치게 생각하고 있다고 생각합니다.

styles.setBold(true) 그리고 styles.setItalic(false)괜찮아

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.