이 반 패턴의 이름은? 지역 변수로서의 필드 [닫기]

검토중인 일부 코드에서 다음과 같은 도덕적 인 내용을보고 있습니다.

public class Foo
{
    private Bar bar;

    public MethodA()
    {
        bar = new Bar();
        bar.A();
        bar = null;
    }

    public MethodB()
    {
        bar = new Bar();
        bar.B();
        bar = null;
    }
}

이 필드 bar논리적 으로 지역 변수입니다. 값은 메소드 호출에서 지속되지 않습니다. 그러나 많은 메소드 Foo가 유형의 오브젝트를 필요로하기 Bar때문에 원래 코드 작성자는 유형 필드를 작성했습니다 Bar.

  1. 이것은 분명히 나쁘지 않습니까?
  2. 이 반 패턴의 이름이 있습니까?


답변

이것은 분명히 나쁘지 않습니까?

네.

  • 메소드를 재진입 할 ​​수 없게하므로 동일한 인스턴스에서 재귀 적으로 또는 다중 스레드 컨텍스트에서 호출되는 경우 문제가됩니다.

  • 다시 호출을 잊어 버린 경우 한 통화에서 다른 통화로의 상태가 누출됨을 의미합니다.

  • 코드가 실제로 무엇을하는지 확인하기 위해 위의 내용을 확인해야하기 때문에 코드를 이해하기 어렵습니다. (로컬 변수 사용과 대조)

  • Foo인스턴스를 필요한 것보다 크게 만듭니다 . (그리고 N 변수에 대해 이것을하는 것을 상상해보십시오 …)

이 반 패턴의 이름이 있습니까?

IMO는 반 패턴이라고 부를 자격이 없습니다. 그것은 나쁜 코딩 습관 / Java 구문 / 쓰레기 코드의 오용입니다. 학생이 강의를 건너 뛰거나 프로그래밍에 적성하지 않은 경우 학부 코드에서 볼 수있는 종류입니다. 프로덕션 코드에서 볼 수 있다면 더 많은 코드 검토를 수행해야한다는 신호입니다 …


기록을 작성하는 올바른 방법은 다음과 같습니다.

public class Foo
{
    public methodA()
    {
        Bar bar = new Bar();  // Use a >>local<< variable!!
        bar.a();
    }

    // Or more concisely (in this case) ...
    public methodB()
    {
        new Bar().b();
    }
}

Java 식별자에 허용되는 스타일 규칙에 맞게 메서드 및 변수 이름도 수정했습니다.


답변

변수에 대해 불필요한 큰 범위라고 부릅니다. 이 설정은 또한 다중 스레드가 MethodA 및 MethodB에 액세스하는 경우 경쟁 조건을 허용합니다.


답변

이것은로 알려진 일반적인 패턴의 특정한 경우입니다 global doorknobbing. 집을 지을 때는 손잡이를 하나만 사서 주위에 두는 것이 좋습니다. 누군가가 문이나 찬장을 사용하고 싶을 때, 그들은 단지 하나의 글로벌 문 손잡이를 잡습니다. 손잡이가 비싸면 좋은 디자인이 될 수 있습니다.

불행히도 친구가 와서 손잡이가 동시에 두 곳에서 사용되면 현실이 산산조각납니다. 문 손잡이가 너무 비싸서 하나만 감당할 수 있다면 사람들이 문 손잡이를 안전하게 돌릴 수있는 시스템을 구축하는 것이 좋습니다.

이 경우 도어 손잡이는 참조 용이므로 저렴합니다. 손잡이가 실제 객체이고 참조가 아닌 객체를 재사용하는 경우에는 값이 충분할 수 있습니다 prudent global doorknob. 그러나 값이 싸면이라고합니다 cheapskate global doorknob.

귀하의 예는 cheapskate다양합니다.


답변

여기서 가장 큰 관심사는 동시성입니다. Foo를 여러 스레드에서 사용하는 경우 문제가 있습니다.

그 외에도 지역 변수는 자체 수명주기를 완벽하게 관리합니다. 더 이상 유용하지 않을 때 무효화해야하는 인스턴스 변수로 바꾸면 오류가 발생합니다.


답변

“가변 재사용”이라는 측면이있는 “부적절한 범위 지정”사례입니다.


답변

안티 패턴이 아닙니다. 반 패턴에는 좋은 생각처럼 보이게하는 속성이있어 사람들이 의도적으로이를 수행하게합니다. 그것들은 패턴으로 계획된 다음 아주 잘못됩니다.

또한 어떤 부분이 패턴, 반 패턴 또는 일반적으로 잘못 적용되는 패턴인지에 대해 논쟁을 불러 일으키는 부분이기도합니다.

이것은 단지 잘못이다.

조금 더 추가합니다.

이 코드는 미신적이거나 기껏해야화물 컬트 관행입니다.

미신은 분명한 정당화없이 행해지는 것입니다. 실제와 관련이있을 수 있지만 연결은 논리적이지 않습니다.

카고 컬트 관행은 지식이 풍부한 소스에서 배운 것을 복사하려고 시도하지만 실제로는 프로세스가 아닌 표면 인공물을 복사하는 것입니다 (파푸아 뉴기니 컬트의 이름을 따서 명 명함) 2 차 세계 대전 일본과 미국 비행기가 돌아 오기를 희망하면서 대나무로 된 비행기 조종 라디오.

이 두 경우 모두 실제 사례는 없습니다.

안티 패턴은 소규모 (처리해야 할 추가 사례를 처리하기위한 추가 브랜치, 스파게티 코드로 이어짐) 또는 매우 의도적으로 패턴을 구현하는 대규모에서 합리적인 개선을 시도합니다. 일부는 쓰기 전용 (예 : 로깅 객체 또는 읽기 전용 (예 : 구성 설정 객체)을 제외한 일부는 싱글 톤을 설명하고 일부는이를 비난 할 수도 있음) 또는 다른 곳에서 해결하는 경우 잘못된 문제 (.NET이 처음 등장했을 때 MS는 관리되지 않는 필드와 일회용 관리 필드가 모두있을 때 처리하는 패턴을 권장했습니다. 실제로 그 상황을 잘 처리하지만 실제 문제는 같은 클래스의 두 유형의 필드).

따라서 반 패턴은 언어, 문제 영역 및 사용 가능한 라이브러리를 잘 알고있는 현명한 사람이 의도적으로 할 수있는 일이며, 여전히 단점을 압도하는 단점이 있습니다.

우리 중 어느 누구도 주어진 언어, 문제 영역 및 사용 가능한 라이브러리에 대해 잘 알지 못하기 때문에 합리적인 솔루션에서 다른 솔루션으로 갈 때 누군가가 무언가를 놓칠 수 있기 때문에 (예를 들어, 필드에 무언가를 잘 사용하기 위해 저장하기 시작한 다음 시도) 그것을 리팩토링하지만 작업을 완료하지 않으면 문제와 같은 코드로 끝날 것입니다.) 우리는 때때로 학습에서 물건을 놓치므로 언젠가는 미신적이거나화물이 많은 코드를 만들었습니다. . 좋은 점은 실제로 안티 패턴보다 식별하고 수정하는 것이 더 명확하다는 것입니다. 진정한 반 패턴은 반 패턴이 아닐 수도 있고, 매력적인 품질을 가지고 있거나, 불량으로 식별 된 경우에도 적어도 반항 할 수있는 방법을 가지고 있습니다. 다른쪽으로 이어집니다).


답변

(1) 좋지 않다고 말할 것입니다.

스택이 로컬 변수를 사용하여 자동으로 수행 할 수 있도록 수동 하우스 유지를 수행합니다.

“새”를 각 메소드 호출이라고 부르므로 성능상의 이점은 없습니다.

편집 : 막대 포인터가 항상 클래스 수명 동안 메모리를 차지하기 때문에 클래스의 메모리 공간이 더 큽니다. 막대 포인터가 로컬 인 경우 메소드 호출 수명 동안 메모리 만 사용합니다. 포인터에 대한 기억은 바다에서 떨어질 뿐이지 만 여전히 불필요합니다.

바는 클래스의 다른 메소드에 표시됩니다. bar를 사용하지 않는 메소드는이를 볼 수 없습니다.

상태 기반 오류. 이 특별한 경우에는 “new”가 매번 호출되므로 상태 기반 오류는 멀티 스레딩에서만 발생해야합니다.

(2) 실제로는 하나의 문제가 아니라 몇 가지 문제이므로 이름이 있는지 모르겠습니다.
-자동 사용 가능시 수동 하우스 키핑-
불필요한 상태-
수명 이상 오래 살 수 있는 상태-
가시성 또는 범위가 너무 큼