생성자 또는 setter 메소드를 사용 하시겠습니까?


16

Action클래스 가있는 UI 코드를 작성하고 있습니다.

public class MyAction extends Action {
    public MyAction() {
        setText("My Action Text");
        setToolTip("My Action Tool tip");
        setImage("Some Image");
    }
}

이 Action 클래스를 만들 때 Action클래스를 사용자 정의 할 수없는 것으로 가정했습니다 (어떤 의미에서 텍스트, 툴팁 또는 이미지는 코드의 어느 곳에서도 변경되지 않습니다). 이제 코드의 특정 위치에서 작업 텍스트를 변경해야합니다. 그래서 동료가 생성자에서 하드 코딩 된 작업 텍스트를 제거하고 인수로 수락하여 모든 사람이 작업 텍스트를 전달하도록 제안했습니다. 아래 코드와 같은 것-

public class MyAction extends Action {
    public MyAction(String actionText) {
        setText(actionText);
        setTooltip("My Action tool tip"); 
        setImage("My Image"); 
    }
}

그러나 그는 setText()메소드가 기본 클래스에 속하기 때문에 액션 인스턴스가 생성 될 때마다 액션 텍스트를 유연하게 전달하는 데 사용될 수 있다고 생각합니다 . 이렇게하면 기존 MyAction클래스 를 변경할 필요가 없습니다 . 그의 코드는 다음과 같습니다.

MyAction action = new MyAction(); //this creates action instance with the hardcoded text
action.setText("User required new action text"); //overwrite the existing text.

그것이 문제를 해결하는 올바른 방법인지 확실하지 않습니다. 나는 위에서 언급 한 경우에 사용자가 어쨌든 텍스트를 변경할 것이라고 생각합니다. 그래서 액션을 구성하는 동안 그를 강요하지 않습니까? 원래 코드에서 볼 수있는 유일한 이점은 사용자가 텍스트 설정에 대해 많이 생각하지 않고도 Action 클래스를 만들 수 있다는 것입니다.


1
사용중인 언어로 과부하 생성자를 허용하지 않습니까?
Mat

1
Java를 사용하고 있습니다. 예, 가능합니다.이를 해결하는 한 가지 방법이 될 수 있습니다.
zswap

2
사실 이후에 클래스 멤버를 설정할 수있는 공개적인 방법이 없다면 클래스는 사실상 불변 입니다. 공용 세터를 허용하면 클래스가 변경 가능해지며 불변성에 의존하는 경우이를 고려해야합니다.
cbojar

객체가 유효하도록 설정 해야하는 경우 모든 생성자에 배치하십시오 ... 선택적 (합리적 기본값이 있음)이고 불변성에 신경 쓰지 않으면 setter에 넣으십시오. 객체를 유효하지 않은 상태로 인스턴스화하거나 인스턴스화 후 가능할 때마다 유효하지 않은 상태로 만드는 것은 불가능합니다.
Bill K

답변:


15

원래 코드에서 볼 수있는 유일한 이점은 사용자가 텍스트 설정에 대해 많이 생각하지 않고도 Action 클래스를 만들 수 있다는 것입니다.

그것은 실제로 이점이 아니며, 대부분의 경우 단점이며 나머지 경우에는 그것을 넥타이라고 부릅니다. 생성 후 누군가가 setText () 호출을 잊어 버린 경우 어떻게해야합니까? 비정상적인 경우, 아마도 오류 처리기 인 경우에는 어떻게됩니까? 실제로 텍스트를 강제로 설정하려면 컴파일 타임 오류 만 실제로 치명적 이기 때문에 컴파일시 강제로 텍스트를 설정해야합니다 . 런타임에 발생하는 것은 실행되는 특정 코드 경로에 따라 다릅니다.

앞으로 두 가지 분명한 길을 봅니다.

  1. 제안한대로 생성자 매개 변수를 사용하십시오. 정말로 원한다면 null빈 문자열을 전달 하거나 전달할 수 있지만 텍스트를 할당하지 않는다는 사실은 암시 적이 아니라 명시 적입니다. null매개 변수 의 존재를 쉽게 볼 수 있고 아마도 그것에 대한 생각이 있었지만 메서드 호출의 부족을 확인하고 의도하지 않은지 여부를 결정하는 것은 쉽지 않습니다. 이와 같은 간단한 경우에는 아마도 내가 취할 접근법 일 것입니다.
  2. 팩토리 / 빌더 패턴을 사용하십시오. 이것은 간단한 시나리오에서는 과잉이 될 수 있지만,보다 일반적인 경우에는 객체를 인스턴스화하기 전 또는 도중에 여러 개의 매개 변수를 설정하고 사전 조건을 확인할 수 있으므로 매우 유연합니다. 또는 클래스를 여러 가지 방법으로 사용할 수 있다면 이점 이 될 수 있습니다 ). 특히 Java에서는 일반적인 관용구이며 사용하는 언어 및 프레임 워크에서 설정된 패턴을 따르는 것이 거의 나쁘지 않습니다.

10

생성자 오버로드는 다음과 같이 간단하고 간단한 솔루션입니다.

public class MyAction extends Action {
    public MyAction(String actionText) {
        setText(actionText);
        setTooltip("My Action tool tip"); 
        setImage("My Image"); 
    }
    public MyAction() {
        this("My Action Text");
    }
}

.setText이 방법으로 덮어 쓸 필요가 없으므로 actionText처음부터 의도 한 것이 될 수 있기 때문에 나중에 호출하는 것이 좋습니다 .

코드가 발전함에 따라 더 많은 유연성이 필요합니다 (확실히 발생할 것임). 또 다른 답변에서 제안한 팩토리 / 빌더 패턴의 이점이 있습니다.


두 번째 속성을 사용자 정의하려는 경우 어떻게됩니까?
케빈 클라인

3
2, 3, .. 속성의 경우 동일한 기술을 적용 할 수 있지만 사용자 정의하려는 속성이 많을수록 다루기가 더 어려워집니다. 어느 시점에서 팩토리 / 빌더 패턴을 구현하는 것이 더 합리적 일 것이라고 @ michael-kjorling은 그의 대답에서 말했다.
janos 2016 년

6

유창한 'setText'메소드를 추가하십시오.

public class MyAction ... {
  ...
  public MyAction setText(String text) { ... ; return this; }
}

MyAction a = new MyAction().setText("xxx");

그보다 더 명확한 것은 무엇입니까? 다른 사용자 정의 가능 특성을 추가하기로 결정한 경우 아무런 문제가 없습니다.


+1, 동의하며 더 많은 속성을 보완하는 다른 답변을 추가했습니다. 유창한 API는 예를 들어 하나 이상의 단일 속성이있을 때 이해하기 쉽다고 생각합니다.
Machado

나는 불변의 객체를 생성하는 빌더를 위해 유창한 인터페이스를 좋아합니다! 매개 변수가 많을수록 더 잘 작동합니다. 그러나이 질문의 특정 예제를 setText()보면 MyAction이 상속하는 Action 클래스에 정의되어 있다고 생각합니다 . 이미 void 반환 유형이있을 수 있습니다.
GlenPeterson 2016 년

1

마찬가지로 케빈 클라인이 그의 대답했다, 내가 갈 수있는 방법은 만드는 것입니다 생각 유창하게 API를 . 유창한 API를 사용할 수있는 속성이 둘 이상있을 때 유창한 API가 더 잘 작동한다고 덧붙이고 싶습니다.

그것은 당신의 코드를보다 읽기 쉽게, 그리고 더 쉽게 내 관점에서하고, AHAM , 쓰기에 "섹시한".

귀하의 경우 다음과 같이 진행됩니다 (오타가 유감스럽게도 마지막 Java 프로그램을 작성한 지 1 년이 지났습니다).

 public class MyAction extends Action {
    private String _text     = "";
    private String _tooltip  = "";
    private String _imageUrl = "";

    public MyAction()
    {
       // nothing to do here.
    }

    public MyAction text(string value)
    {
       this._text = value;
       return this;
    }

    public MyAction tooltip(string value)
    {
       this._tooltip = value;
       return this;
    }

    public MyAction image(string value)
    {
       this._imageUrl = value;
       return this;
    }
}

사용법은 다음과 같습니다.

MyAction action = new MyAction()
    .text("My Action Text")
    .tooltip("My Action Tool tip")
    .image("Some Image");

나쁜 생각, 텍스트 나 중요한 것을 설정하는 것을 잊어 버리면 어떨까요?
Prakhar

1

생성자 또는 빌더를 사용하는 조언은 일반적으로 좋지만 내 경험상 Actions의 몇 가지 핵심 사항이 누락되었습니다.

  1. 국제화해야 할 수도 있습니다.
  2. 마지막 순간에 마케팅이 변경 될 가능성이 있습니다.

속성 파일, XML 등에서 이름, 툴팁, 아이콘 등을 읽을 것을 강력히 권장합니다. 예를 들어, 파일 열기 작업의 경우 속성을 전달할 수 있습니다.

File.open.name=Open
File.open.tooltip=Open a file
File.open.icon=somedir/open.jpg

이것은 프로그래밍 시간이나 재 컴파일없이 새로운 더 나은 아이콘 등을 시도하기 위해 프랑스어로 번역하기에 매우 쉬운 형식입니다.

이것은 대략적인 개요 일뿐입니다. 독자에게는 많은 것이 남아 있습니다. 다른 국제화 사례를 찾아보십시오.


0

생성자 내에서 setText (actionText) 또는 setTooltip ( "My action tool tip")을 호출하는 것은 쓸모가 없습니다. 해당 필드를 직접 초기화하면 더 쉽고 성능이 향상됩니다.

    public MyAction(String actionText) {
        this.actionText = actionText;
    }

MyAction 해당 오브젝트의 수명 동안 actionText를 변경하는 경우 setter 메소드를 배치해야합니다. setter 메소드를 제공하지 않고 생성자에서만 필드를 초기화하지 않는 경우

툴팁과 이미지는 상수이므로 상수로 취급하십시오. 필드가 있습니다 :

private (or even public) final static String TOOLTIP = "My Action Tooltip";

사실, 빈 객체 (엄격히 데이터 구조를 나타내는 객체가 아닌)를 디자인 할 때, setter와 getter는 일종의 break encapsulation을 제공하기 때문에 나쁜 아이디어입니다.


4
중간급 호환 컴파일러와 JITter는 setText () 등 호출을 인라인해야하므로 할당을 수행하는 함수 호출과 함수 호출 대신 해당 할당을 갖는 성능 차이는 거의 무시할 수 있어야합니다. 0이 아닙니다.
CVn

0

직원, 부서를 업데이트하는 데 사용되는 업데이트와 같은 일반 작업 클래스를 만들려는 경우 이것이 사실이라고 생각합니다. 그것은 모두 시나리오에 달려 있습니다. 특정 직원 (업데이트 직원과 같은) 클래스 (응용 프로그램에서 많은 위치를 사용함-직원 업데이트)가 응용 프로그램의 모든 위치에 동일한 텍스트, 툴팁 및 이미지를 유지하도록 일관성있게 작성됩니다 (일관성 관점). 따라서 텍스트, 툴팁 및 이미지에 대한 하드 코딩을 수행하여 기본 텍스트, 툴팁 및 이미지를 제공 할 수 있습니다. 더 많은 유연성을 제공하고 사용자 정의하려면 해당 setter 메소드가 있어야합니다. 우리가 변경해야 할 장소는 10 %에 불과합니다. 사용자로부터 매번 작업 텍스트를 가져 오면 동일한 작업에 대해 매번 다른 텍스트가 발생할 수 있습니다. 'Update Emp', 'Update Employee', 'Change Employee'또는 'Edit Employee'와 같이.


오버로드 된 생성자가 여전히 문제를 해결해야한다고 생각합니다. 모든 "10 %"의 경우, 먼저 기본 텍스트를 사용하여 조치를 작성한 후 "setText ()"메소드를 사용하여 조치 텍스트를 변경하십시오. 액션을 구성하는 동안 적절한 텍스트를 설정하지 않는 이유는 무엇입니까?
zswap

0

인스턴스 사용 방법을 생각하고 사용자가 해당 인스턴스를 올바른 또는 최소한 최상의 방식으로 사용하도록 안내하거나 강요하는 솔루션을 사용하십시오. 이 클래스를 사용하는 프로그래머는 걱정하고 생각할 다른 것들이 많이 있습니다. 이 클래스는 목록에 추가해서는 안됩니다.

예를 들어, MyAction 클래스가 생성 후 변경 불가능한 것으로 가정하면 (및 다른 초기화 가능) setter 메소드가 없어야합니다. 대부분의 경우 기본 "내 작업 텍스트"를 사용하는 경우 매개 변수가없는 생성자와 옵션 텍스트를 허용하는 생성자가 있어야합니다. 이제 사용자는 90 %의 시간을 올바르게 사용할 필요가 없습니다. 사용자가 일반적으로 텍스트에 대해 생각 해야하는 경우 매개 변수가없는 생성자를 건너 뜁니다. 이제 사용자는 필요할 때 생각해야하며 필요한 단계를 간과 할 수 없습니다.

경우 MyAction인스턴스가 전체 건설 후 변경할 수 있어야 당신은 텍스트에 대한 세터가 필요합니다. 생성자에서 값을 설정하는 것을 건너 뛰려고합니다 (DRY 원칙- "반복하지 마십시오"). 기본값이 충분하면 일반적으로 충분합니다. 그러나 그렇지 않은 경우 생성자의 텍스트를 요구하면 사용자는 언제 생각해야하는지 생각하게됩니다.

이 사용자 는 바보가 아닙니다 . 그들은 걱정할 실제 문제가 너무 많습니다. 수업의 "인터페이스"에 대해 생각함으로써, 실제 문제는 물론 불필요한 문제가되지 않도록 할 수 있습니다.


0

다음 제안 된 솔루션에서 수퍼 클래스는 추상적이며 세 멤버 모두 기본값으로 설정되어 있습니다.

서브 클래스는 생성자가 다르기 때문에 프로그래머가 인스턴스화 할 수 있습니다.

첫 번째 생성자를 사용하면 모든 멤버가 기본값을 갖습니다.

두 번째 생성자를 사용하는 경우 actionText 멤버에 초기 값을 지정하여 다른 두 멤버를 기본값으로 둡니다.

세 번째 생성자를 사용하는 경우 actionText 및 toolTip의 새 값으로 인스턴스화하고 imageURl을 기본값으로 남겨 둡니다.

등등.

public abstract class Action {
    protected String text = "Default action text";
    protected String toolTip = "Default action tool tip";
    protected String imageURl = "http://myserver.com/images/default.png";

    .... rest of code, I guess setters and getters
}

public class MyAction extends Action {


    public MyAction() {

    }

    public MyAction(String actionText) {
        setText(actionText);
    }

    public MyAction(String actionText, String toolTip_) {
        setText(actionText);
        setToolTip(toolTip_);   
    }

    public MyAction(String actionText, String toolTip_; String imageURL_) {
        setText(actionText);
        setToolTip(toolTip_);
        setImageURL(imageURL_);
    }


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