생성자 또는 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.