피해야 할 디자인 패턴 [닫기]


105

많은 사람들이 Singleton 패턴에 여러 가지 단점이 있으며 일부는 패턴을 완전히 피할 것을 제안한다는 데 동의하는 것 같습니다. 여기에 훌륭한 토론이 있습니다 . Singleton 패턴에 대한 의견을 해당 질문으로 보내주십시오.

내 질문 : 피하거나 세심한주의를 기울여 사용해야하는 다른 디자인 패턴이 있습니까?


Design Antipatterns deviq.com/antipatterns
개발자

@casperOne 왜 질문을 닫았습니까? 문제는 합법적이었습니다.
bleepzter

답변:


149

패턴이 복잡함

모든 디자인 패턴은주의해서 사용해야합니다. 제 생각 에는 패턴을 즉시 구현하는 대신 타당한 이유가있을 때 패턴을 리팩토링해야합니다 . 패턴 사용의 일반적인 문제는 복잡성을 추가한다는 것입니다. 패턴을 과도하게 사용하면 특정 응용 프로그램이나 시스템을 추가로 개발하고 유지 관리하기가 번거로워집니다.

대부분의 경우 간단한 솔루션이 있으며 특정 패턴을 적용 할 필요가 없습니다. 경험상 좋은 규칙은 코드 조각이 대체되거나 자주 변경되어야 할 때마다 패턴을 사용하고 패턴을 사용할 때 복잡한 코드에 대한주의를 기울일 준비를하는 것입니다.

기억 당신의 목표는 단순해야 하고 당신이 당신의 코드에서 지원 변화에 대한 실제적인 필요를 볼 경우 패턴을 사용합니다.

패턴에 대한 원칙

패턴이 과도하게 엔지니어링되고 복잡한 솔루션으로 이어질 수 있다면 패턴을 사용하는 것이 문제처럼 보일 수 있습니다. 그러나 프로그래머가 대부분의 패턴에 대한 토대가되는 디자인 기술과 원칙 을 읽는 것이 훨씬 더 흥미 롭습니다 . 실제로 내가 가장 좋아하는 '디자인 패턴'책 중 하나는 문제의 패턴에 적용 할 수있는 원칙을 반복함으로써이를 강조합니다. 관련성 측면에서 패턴보다 유용 할 정도로 간단합니다. 일부 원칙은 코드 모듈을 빌드 할 수있는 한 Liskov Substitution Principle 과 같은 객체 지향 프로그래밍 (OOP) 이상을 포함하기에 충분히 일반적 입니다.

다양한 디자인 원칙이 있지만 GoF 책첫 번째 장에 설명 된 내용은 시작하기에 매우 유용합니다.

  • '구현'이 아닌 '인터페이스'로 프로그래밍하십시오. (강 오브 포 1995 : 18)
  • '클래스 상속'보다 '객체 구성'을 선호하십시오. (강 오브 포 1995 : 20)

잠시 동안 당신에게 가라 앉게하십시오. GoF가 작성되었을 때 인터페이스 는 추상화 (슈퍼 클래스를 의미하기도 함)를 의미하며 Java 또는 C #의 유형 인 인터페이스와 혼동해서는 안됩니다. 두 번째 원칙은 오늘날에도 여전히 흔히 볼 수 있는 상속의 남용에서 비롯됩니다 .

여기에서 Robert Cecil Martin (일명 Bob 삼촌)알려준 SOLID 원칙 을 읽을 수 있습니다 . Scott Hanselman 은 이러한 원칙 에 대한 팟 캐스트 에서 Bob 삼촌을 인터뷰했습니다 .

  • S 화롯불 책임 원칙
  • O 펜 폐쇄 원리
  • L iskov 대체 원칙
  • 나는 독방 원리를 nterface
  • D의 ependency 반전 원리

이러한 원칙은 동료들과 함께 읽고 토론하기에 좋은 출발점이됩니다. 원칙이 서로, 그리고 관심사 분리종속성 주입 과 같은 다른 프로세스와 얽혀 있음을 알 수 있습니다 . TDD 를 한동안 수행 한 후에 는 분리 되고 반복 가능한 단위 테스트 를 생성하기 위해 어느 정도 따라야하기 때문에 이러한 원칙이 실제로 실제로 온다는 것을 알 수 있습니다 .


7
+1 아주 좋은 답변입니다. 오늘날 모든 (초보자) 프로그래머는 자신의 디자인 패턴을 알고 있거나 적어도 존재한다는 것을 알고있는 것 같습니다. 그러나 코드의 복잡성을 관리하기 위해 단일 책임과 같은 절대적으로 필수적인 원칙 중 일부를 적용하는 것은 말할 것도없고 들어 본 적이없는 사람이 매우 많습니다.
eljenso

21

Design Patterns의 저자가 가장 걱정하는 것은 "Visitor"패턴이었습니다.

그것은 "필요한 악"이지만 종종 과도하게 사용되며 그 필요성은 종종 디자인에 더 근본적인 결함을 드러냅니다.

"Visitor"패턴의 대체 이름은 "Multi-dispatch"입니다. 방문자 패턴은 단일 유형의 디스패치 OO 언어를 사용하여 두 유형을 기반으로 사용할 코드를 선택하려는 경우에 끝나는 것이기 때문입니다. (또는 그 이상) 다른 개체.

고전적인 예는 두 모양 사이에 교차점이 있지만 종종 간과되는 훨씬 더 간단한 경우가 있습니다. 두 이기종 개체의 동등성을 비교하는 것입니다.

어쨌든 종종 다음과 같은 결과를 얻습니다.

interface IShape
{
    double intersectWith(Triangle t);
    double intersectWith(Rectangle r);
    double intersectWith(Circle c);
}

이것의 문제점은 "IShape"의 모든 구현을 결합했다는 것입니다. 계층 구조에 새 모양을 추가 할 때마다 다른 모든 "모양"구현도 변경해야한다는 것을 암시했습니다.

때때로 이것은 올바른 최소한의 디자인이지만 충분히 생각해보십시오. 당신의 디자인은 않습니다 정말 당신이 두 가지 유형에 파견 할 필요가 있음을 의무화? 다중 방법의 조합 폭발 각각을 작성 하시겠습니까?

종종 다른 개념을 도입하여 실제로 작성해야하는 조합의 수를 줄일 수 있습니다.

interface IShape
{
    Area getArea();
}

class Area
{
    public double intersectWith(Area otherArea);
    ...
}

물론, 상황에 따라 다릅니다. 때로는 이러한 모든 사례를 처리하기 위해 코드를 작성해야 할 때가 있습니다.하지만 잠시 멈춰서 잠시 생각하고 비지터를 사용하는 것이 좋습니다. 나중에 많은 고통을 덜어 줄 수 있습니다.


2
방문자에 대해 말하면서 Bob 삼촌은 "항상"사용합니다. butunclebob.com/ArticleS.UncleBob.IuseVisitor
Spoike

3
@Paul Hollingsworth Design Patterns 작성자가 걱정하는 부분 (그리고 왜 걱정 하는가)에 대한 참조를 제공 할 수 있습니까?
m3th0dman 2013 년

16

싱글 톤-싱글 톤 X를 사용하는 클래스는보기 어렵고 테스트를 위해 분리하기 어려운 종속성이 있습니다.

편리하고 이해하기 쉽기 때문에 자주 사용되지만 테스트를 정말 복잡하게 만들 수 있습니다.

Singletons are Pathological Liars를 참조하십시오 .


1
또한 Mock 객체를 주입 할 수있는 단일 지점을 제공 할 수 있으므로 테스트를 간단히 수행 할 수 있습니다. 균형을 맞추는 것이 전부입니다.
Martin Brown

1
@Martin : 물론 테스트를 위해 singelton을 변경할 수 있다면 (표준 singelton 구현을 사용하지 않는 경우) 생성자에서 테스트 구현을 통과하는 것보다 얼마나 쉬운가요?
orip

14

템플릿 메서드 패턴은 일반적으로 매우 위험한 패턴이라고 생각합니다.

  • "잘못된 이유로"상속 계층 구조를 많이 사용합니다.
  • 기본 클래스는 모든 종류의 관련없는 코드로 흩어져있는 경향이 있습니다.
  • 이는 종종 개발 프로세스 초기에 디자인을 잠그도록합니다. (많은 경우 조기 잠금)
  • 나중 단계에서 이것을 변경하는 것은 점점 더 어려워집니다.

2
템플릿 방법을 사용할 때마다 전략을 사용하는 것이 더 좋습니다. TemplateMethod의 문제는 기본 클래스와 파생 클래스 사이에 재진입이 있다는 것입니다.
Paul Hollingsworth

5
@Paul : 템플릿 방법은 적절하게 사용할 때, 즉 다양한 부분이 그렇지 않은 부분에 대해 많이 알아야 할 때 좋습니다. 필자는 기본 코드가 사용자 지정 코드 만 호출 할 때 전략을 사용해야하고 사용자 지정 코드가 기본 코드에 대해 알아야하는 경우 템플릿 메서드를 사용해야한다는 것입니다.
dsimcha 2010 년

네 딤차, 동의합니다 ... 클래스 디자이너가 이것을 알고있는 한.
Paul Hollingsworth

9

DP (Design Patterns)를 피해야한다고 생각하지 않으며 아키텍처를 계획 할 때 DP를 사용하도록 강요해서는 안된다고 생각합니다. DP는 계획에서 자연스럽게 나올 때만 사용해야합니다.

처음부터 주어진 DP를 사용하기를 원한다고 정의하면, 우리가 선택한 DP가 우리의 요구에 적합하다는 보장없이 미래의 많은 디자인 결정이 그 선택의 영향을받을 것입니다.

또한 우리가해서는 안되는 한 가지는 DP를 불변의 개체로 취급하는 것입니다. 우리는 패턴을 우리의 필요에 맞게 조정해야합니다.

요약하자면, DP를 피해서는 안된다고 생각합니다. 이미 아키텍처에서 형태를 취하고있을 때이를 수용해야합니다.


7

Active Record는 비즈니스 로직과 지속성 코드를 혼합하도록 장려하는 남용 된 패턴이라고 생각합니다. 모델 계층에서 스토리지 구현을 숨기고 모델을 데이터베이스에 연결하는 데는 그다지 좋은 일이 아닙니다. 테이블 데이터 게이트웨이, 행 데이터 게이트웨이 및 데이터 매퍼와 같이 종종 더 나은 솔루션을 제공하고 스토리지에 더 나은 추상화를 제공하는 데 도움이되는 많은 대안 (PoEAA에 설명 됨)이 있습니다. 또한 모델을 데이터베이스에 저장할 필요 가 없습니다 . XML로 저장하거나 웹 서비스를 사용하여 액세스하는 것은 어떻습니까? 모델의 저장 메커니즘을 변경하는 것이 얼마나 쉬울까요?

즉, Active Record가 항상 나쁜 것은 아니며 다른 옵션이 과도 할 수있는 간단한 응용 프로그램에 적합합니다.


1
사실이지만 구현에 어느 정도 의존합니다.
Mike Woodhouse

6

그것은 간단합니다 ... 당신에게 명확하지 않은 디자인 패턴 이나 당신이 편안하지 않은 디자인 패턴을 피하십시오 .

일부 이름을 ...

다음과 같은 비실용적 인 패턴 이 있습니다 .

  • Interpreter
  • Flyweight

다음 과 같이 이해하기 어려운 것도 있습니다 .

  • Abstract Factory -생성 된 개체의 가족이있는 전체 추상적 인 공장 패턴은 보이는 것만 큼 산들 바람이 아닙니다.
  • Bridge -추상화와 구현이 하위 트리로 나뉘어지면 너무 추상적이 될 수 있지만 경우에 따라 매우 유용한 패턴입니다.
  • Visitor -더블 디스패치 메커니즘 이해는 정말 필수입니다.

매우 단순 해 보이지만 원칙이나 구현과 관련된 다양한 이유로 선택이 명확하지 않은 일부 패턴이 있습니다 .

  • Singleton -정말 나쁜 패턴은 아니지만 너무 많이 사용됨 (종종 거기에 적합하지 않은 경우)
  • Observer -훌륭한 패턴 ... 코드를 읽고 디버그하기가 훨씬 더 어려워집니다.
  • Prototype -컴파일러 검사에서 역 동성을 확인합니다 (좋거나 나쁠 수 있음 ...에 따라 다름).
  • Chain of responsibility -너무 자주 강제로 / 인위적으로 디자인에 밀어 넣음

일반적으로 어딘가에 더 우아한 솔루션이 있기 때문에 이러한 "실용적이지 않은 것"의 경우 사용하기 전에 실제로 고려해야합니다.

"잡기 어려운"사람들에게는 ... 적절한 장소에서 사용하고 잘 구현 될 때 정말 큰 도움이되지만 부적절하게 사용되면 악몽입니다.

자, 다음은 ...


플라이 웨이트 패턴은 리소스 (종종 이미지)를 두 번 이상 사용할 때 항상 필수입니다. 그것은 패턴이 아니라 해결책입니다.
Cengiz Kandemir

5

이것 때문에 너무 많이 맞지 않기를 바랍니다. Christer Ericsson은 실시간 충돌 감지 블로그 에서 디자인 패턴에 대한 두 개의 기사 ( 1 , 2 )를 작성했습니다 . 그의 어조는 다소 거칠고 도발적 일 수도 있지만 그 남자는 그의 물건을 알고 있기 때문에 나는 그것을 미치광이의 열광이라고 무시하지 않을 것입니다.


흥미로운 읽기. 링크 주셔서 감사합니다!
Bombe

3
바보는 잘못된 코드를 생성합니다. 패턴이있는 바보가 패턴을 본 적이없는 바보보다 더 나쁜 코드를 생성합니까? 나는 그들이 그렇게 생각하지 않는다. 똑똑한 사람들에게 패턴은 아이디어 교환을 용이하게하는 잘 알려진 어휘를 제공합니다. 해결책 : 패턴을 배우고 똑똑한 프로그래머 만 다루십시오.
Martin Brown

나는 진정한 바보가 어떤 도구를 사용하든 상관없이 더 나쁜 코드를 생성하는 것이 실제로 가능하지 않다고 생각합니다
1800 INFORMATION

1
그의 대학 시험에 대한 그의 예는 문제 영역을 경멸하고 주말에 몇 시간 이상 공부하지 않으려는 사람들이 문제 해결을 시도 할 때 잘못된 답을 내놓는다는 것을 증명할 뿐이라고 생각합니다.
scriptocalypse 2011

5

일부는 서비스 로케이터 가 안티 패턴 이라고 말합니다 .


때때로 서비스 로케이터가 필요하다는 점도 중요합니다. 예를 들어 개체의 인스턴스화를 적절하게 제어 할 수없는 경우 (예 : C #에서 상수가 아닌 매개 변수가있는 특성). 그러나 ctor 주입과 함께 서비스 로케이터를 사용할 수도 있습니다.
Sinaesthetic

2

관찰자 패턴에 대한 답이 많고 매우 일반적인 경우에 작동하지만 시스템이 더 복잡 해짐에 따라 OnBefore (), OnAfter () 알림이 필요하고 종종 비동기 작업을 게시하여 재개를 방지해야하는 악몽이됩니다. 초조함. 훨씬 더 나은 솔루션은 계산 중에 모든 개체 액세스 (읽기 장벽 포함)를 계측하고 종속성 그래프에서 자동으로 에지를 생성하는 자동 종속성 분석 시스템을 개발하는 것입니다.


4
"A"라는 단어까지 귀하의 답변에있는 모든 것을 이해했습니다
1800 INFORMATION

설명하는이 자동 종속성 분석을 확장하거나 연결해야 할 수 있습니다. 또한 .NET에서는 관찰자 패턴 대신 대리자 / 이벤트가 사용됩니다.
Spoike

3
@Spoike : 델리게이트 / 이벤트는 관찰자 패턴의 구현입니다
orip

1
Observer에 대한 개인적 원한은 가비지 수집 언어에서 메모리 누수를 일으킬 수 있다는 것입니다. 개체 작업을 마치면 개체가 정리되지 않는다는 것을 기억해야합니다.
Martin Brown

@orip : 네, 그래서 델리게이트 / 이벤트를 사용합니다. ;)
Spoike

2

Spoike의 게시물을 보완하는 Refactoring to Patterns 는 좋은 읽기입니다.


나는 실제로 인터넷에서 책의 카탈로그에 연결했습니다. :)
Spoike

오! 나는 그것을 호버링하는 것을 귀찮게하지 않았다. 사실 질문이 끝나 자마자이 책이 떠오르 더니 답을 보았습니다. 나는 그것을 게시하는 것을 막을 수 없었다. :)
Adeel Ansari

0

반복자는 피해야 할 또 하나의 GoF 패턴이거나 최소한 대안이없는 경우에만 사용합니다.

대안은 다음과 같습니다.

  1. for-each 루프. 이 구조는 대부분의 주류 언어에 존재하며 대부분의 경우 반복자를 방지하는 데 사용할 수 있습니다.

  2. LINQ 또는 jQuery의 선택기. 컨테이너의 모든 개체를 처리해야하는 것은 아니므로 for-each가 적절하지 않을 때 사용해야합니다. 반복기와 달리 선택기는 처리 할 종류의 개체를 한곳에서 확인할 수 있습니다.


선택자에 동의합니다. Foreach는 반복자이며 대부분의 OO 언어는 foreach를 허용하기 위해 구현하는 반복 가능한 인터페이스를 제공합니다.
Neil Aitken

일부 언어에서 각 구성은 반복자를 통해 구현 될 수 있지만 실제로 그 개념은 더 높은 수준이며 선택자에 더 가깝습니다. for-each 개발자는 컨테이너의 모든 요소를 ​​처리해야한다고 명시 적으로 선언합니다.
Volodymyr Frolov

반복자는 훌륭한 패턴입니다. 안티 패턴은 반복자 없이 IEnumerable / IEnumerator 구현 합니다. yield반복자를 통해 LINQ가 가능해 졌다고 생각 합니다. Eric White는 C # 3.0에서 이에 대해 몇 가지 훌륭한 토론을했습니다 : blogs.msdn.com/b/ericwhite/archive/2006/10/04/… . 또한 반복기를 사용하는 코 루틴에 대한 Jeremy Likness의 토론을 확인하세요. wintellect.com/CS/blogs/jlikness/archive/2010/03/23/… .

@Ryan Riley, 반복자는 낮은 수준의 개체이므로 높은 수준의 디자인과 코드에서는 피해야합니다. 반복기 및 다양한 종류의 선택기 구현에 대한 세부 정보는 여기서 중요하지 않습니다. 반복자와 달리 선택기는 프로그래머가 처리하려는 것을 명시 적으로 표현하여 높은 수준이되도록합니다.
Volodymyr Frolov

대체 LINQ와 유사한 F # 구문 인 Fwiw는`List.map (fun x-> x.Value) xs`이며, 이는 목록 이해력만큼 깁니다.
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.