검토중인 일부 코드에서 다음과 같은 도덕적 인 내용을보고 있습니다.
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
.
- 이것은 분명히 나쁘지 않습니까?
- 이 반 패턴의 이름이 있습니까?
답변
이것은 분명히 나쁘지 않습니까?
네.
-
메소드를 재진입 할 수 없게하므로 동일한 인스턴스에서 재귀 적으로 또는 다중 스레드 컨텍스트에서 호출되는 경우 문제가됩니다.
-
다시 호출을 잊어 버린 경우 한 통화에서 다른 통화로의 상태가 누출됨을 의미합니다.
-
코드가 실제로 무엇을하는지 확인하기 위해 위의 내용을 확인해야하기 때문에 코드를 이해하기 어렵습니다. (로컬 변수 사용과 대조)
-
각
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) 실제로는 하나의 문제가 아니라 몇 가지 문제이므로 이름이 있는지 모르겠습니다.
-자동 사용 가능시 수동 하우스 키핑-
불필요한 상태-
수명 이상 오래 살 수 있는 상태-
가시성 또는 범위가 너무 큼