역동적이고 약한 유형의 언어에서 디자인 패턴과 OOP 관행에 대한 생각은 어떻게 변합니까?


11

이 라인들에 이미 상당히 유용한 질문 ( " 비 OOP 디자인 패턴? ")이 있지만, 역동적이고 약한 유형의 언어로 시작하는 사람에 대한 과도기적 인 관점에 대해 더 궁금합니다.

즉, 몇 년 동안 C ++, C # 또는 Java로 프로그래밍을 해왔으며 GoF 디자인 패턴, Fowler 's Enterprise Application Architecture패턴 , SOLID 원칙 등 의 선을 따라 많은 지혜를 흡수했다고 가정 해 봅시다 . Ruby, Python, JavaScript 등을 다루고 지식이 어떻게 적용되는지 궁금합니다. 아마 나는 많은 경우에 직접 번역을 할 수 있었지만 거의 확실하게 새로운 설정을 최대한 활용하지는 못할 것입니다. 오리 타이핑만으로도 많은 인터페이스 기반 사고가 머리에 떠 오릅니다.

무엇이 동일하게 유지됩니까? 어떤 변화가 있습니까? 동적 언어 초보자가 알아야 할 SOLID 또는 표준 패턴 (아마도 완전히 새로운 패턴)과 같은 지침 원리가 있습니까?

답변:


7

무엇이 동일하게 유지됩니까? 어떤 변화가 있습니까?

패턴은 동일합니다. 언어 기술이 바뀝니다.

SOLID와 같은 지침 원리가 있습니까?

예. 실제로, 그들은 지침 원칙으로 남아 있습니다. 아무것도 변하지 않습니다.

또는 동적 언어 초보자가 알아야 할 정식 패턴 (아마도 완전히 새로운 패턴)?

어떤 것들은 독특합니다. 대부분의 영향은 구현 기술이 변경된다는 것입니다.

패턴은 패턴 입니다. 법이 아닙니다. 서브 루틴이 아닙니다. 매크로가 아닙니다. 좋은 생각이기 때문에 반복되는 것이 좋습니다.

좋은 아이디어는 스타일에서 벗어나거나 크게 변하지 않습니다.

다른 메모. 파이썬은 "약한 타입"이 아닙니다. 캐스트 작업이 없기 때문에 Java 또는 C ++보다 형식이 강력합니다. [예, 객체와 관련된 클래스를 퍼지하는 방법이 있지만, 까다 롭고 합법적 인 요점을 증명하는 것 외에는 그런 것이 아닙니다.]

또한. 대부분의 디자인 패턴은 다형성을 이용하는 다양한 방법을 기반으로합니다.

또는 명령 또는 기념물 예로. 여기에는 다형성 상태, 명령 또는 상태 변경에 대한 설명을 생성하는 클래스 계층 구조가 있습니다. 파이썬에서 이것을 할 때 큰 변화는 없습니다. 파이썬의 다형성은 공통 조상이 아닌 일반적인 메소드에 의존하기 때문에 약간의 변경으로 정확한 클래스 계층 구조가 완화됩니다.

또한 일부 패턴은 단순히 바인딩을 지연시키려는 시도입니다. 대부분의 팩토리 관련 패턴은 응용 프로그램의 모든 C ++ 모듈을 다시 컴파일하지 않고도 클래스 계층 구조를 쉽게 변경할 수있게하려는 시도입니다. 이것은 동적 언어에서 흥미로운 최적화가 아닙니다. 그러나 구현 세부 사항을 숨기는 방법으로 팩토리 는 여전히 큰 가치가 있습니다.

일부 패턴은 컴파일러와 링커를 구동하려는 시도입니다. 예를 들어 Singleton 은 혼란스러운 전역을 만들지 만 최소한 캡슐화하기 위해 존재합니다. 파이썬 싱글 톤 클래스는 유망한 전망이 아닙니다. 그러나 파이썬 모듈은 이미 싱글 톤이므로 많은 사람들이 모듈을 사용하고 싱글 톤 클래스 를 망치려고하지 않습니다.


SOLID를 사용하여 "아무것도 변경하지 않는다"고 말하지 않습니다. 언어와 객체 모델에 따라 공개 폐쇄 원칙과 Liskov 대체 원칙은 모두 의미가 없을 수 있습니다. (JavaScript와 Go가 모두
Mason Wheeler

@Mason Wheeler. Open-Closed는 제 경험상 언어에 독립적입니다. JavaScript 또는 Go를 사용하여 닫힌 디자인이 "의미없는"방법에 대한보다 구체적인 예를 제공해야합니다. Liskov 대체는 JavaScript에는 적용되지 않지만 필수 패턴 인 다형성 (polymorphism)은 여전히 ​​적용되는 것으로 보입니다.
S.Lott

@ S.Lott : 편집의 멋진 업데이트; 그들은 원래의 답변보다 훨씬 더 흥미로웠다 : P. 파이썬 실수를 고쳐 주셔서 감사합니다. 일반적으로 특정 패턴 예제와 동적 언어, 다형성, 후기 바인딩 등으로 묶는 방법은 완벽합니다.
Domenic

@ S.Lott : Open / Closed는 상속에 관한 것이기 때문에 해당 언어에는 없습니다. (또한, "수정을 위해 닫힌"객체는 많은 루비 코더와 잘 어울리지 않을 것입니다 ...)
Mason Wheeler

@Mason Wheeler : Open / Closed에 대한 설명을 해주셔서 감사합니다. JavaScript 예외가 중요하다고 생각하지만 질문이 너무 열려 있기 때문에 (JavaScript, Python 및 Ruby 및 ETC라는 언어 나열) 특수 사례를 해결하는 방법을 잘 모르겠습니다.
S.Lott

8

피터 노르 빅의 1998 년 바로이 질문에 갔다 읽을 http://norvig.com/design-patterns/ppframe.htm을 그가 눈치 상세한 것들의 집합, 및 http://c2.com/cgi/wiki?AreDesignPatternsMissingLanguageFeatures을 위해 요점에 대한 추가 토론.

짧은 버전은 언어에 더 많은 기능이있을 때 반복적 인 디자인 패턴이 더 단순 해지는 경향이 있다는 것입니다. 그는 이것이 GoF가 식별 한 대부분의 디자인 패턴에 해당한다는 것을 발견했습니다.


8

동적 객체 지향 언어로 프로그래밍하는 경우 동일한 패턴과 원리를 많이 사용하지만 환경에 따라 약간의 조정 및 차이점이 있습니다.

Duck Typing으로 인터페이스 교체 -Gang of Four는 순수 가상 함수를 사용하여 추상 기본 클래스를 사용하고 동적 언어로 Java 인터페이스를 사용하면 이해가 필요합니다. 어느 곳에서나 객체를 사용할 수 있으며 실제로 호출되는 메소드를 구현하면 제대로 작동하므로 공식적인 인터페이스를 정의 할 필요가 없습니다. 그것은 가치가있을 수 있습니다 문서화 실제로 필요한 것을 분명 그래서 하나.

함수는 객체입니다 -결정과 행동을 분리하는 것과 관련된 많은 패턴이 있습니다. 명령, 전략, 책임의 사슬 등. 일급 함수가있는 언어에서는 .doIt()메소드로 객체를 만드는 대신 단순히 함수를 전달하는 것이 합리적 입니다. 이러한 패턴은 "고차 함수 사용"으로 변환됩니다.

판매 -인터페이스 분리 원칙은 인터페이스가 없기 때문에 가장 큰 인기를 얻었습니다. 여전히 원리를 고려해야하지만 코드로이를 수정할 수는 없습니다. 여기서 오직 개인적인 경계 만이 당신을 보호 할 것입니다. 반대로,이 원칙을 위반함으로써 야기되는 고통은 일반적인 동적 환경에서 훨씬 줄어 듭니다.

"... 내 자신의 특정 ... 관용구!" -각 언어에는 좋은 습관과 나쁜 습관이 있으며, 그 언어로 최고의 코드를 원한다면 배우고 따라야합니다. 완벽하게 작성된 반복자 패턴은 예를 들어 내장 된 목록 이해 기능이있는 언어로 웃어 질 수 있습니다.


3

내 경험상 일부 패턴은 여전히 ​​파이썬에서 유용하며 정적 언어보다 설정하기가 훨씬 쉽습니다. 일부 패턴 OTOH는 싱글 톤 패턴처럼 필요하지 않거나 찡그린 얼굴 일뿐입니다. 대신 모듈 레벨 변수 또는 함수를 사용하십시오. 또는 보그 패턴을 사용하십시오.

생성 패턴을 설정하는 대신 객체를 생성하는 호출 가능 객체를 전달하는 것으로 충분합니다. 파이썬에는 클래스 자체의 호출 __call__이 없기 때문에 함수, 메소드 또는 클래스가 있는 객체 일 수 있습니다 new().

def make_da_thing(maker, other, stuff):
    da_thing = maker(other + 1, stuff + 2)
    # ... do sth
    return da_thing

def maker_func(x, y):
     return x * y

class MakerClass(object):
    def __init__(self, x, y):
        self.x = x
        self.y = y
...
a = make_da_thing(maker_func, 5, 8)
b = make_da_thing(MakerClass, 6, 7)

상태 및 전략 패턴은 C ++ 및 Java와 같은 언어에서 매우 유사한 구조를 공유합니다. 파이썬에서는 그렇지 않다. 전략 패턴은 다소 동일하지만 상태 패턴은 대부분 불필요합니다. 정적 언어의 상태 패턴은 런타임시 클래스 변경을 시뮬레이션합니다. 파이썬에서는 다음과 같이 할 수 있습니다 : 런타임에 객체의 클래스를 변경하십시오. 통제되고 캡슐화 된 방식으로 수행하는 한 괜찮습니다.

class On(object):
    is_on = True
    def switch(self):
        self.__class__ = Off

class Off(object):
    is_on = False
    def switch(self):
        self.__class__ = On
...

my_switch = On()
assert my_switch.is_on
my_switch.switch()
assert not my_switch.is_on

정적 유형 디스패치에 의존하는 패턴은 작동하지 않거나 상당히 다르게 작동합니다. 예를 들어 Visitor Pattern :과 같은 보일러 플레이트 코드를 많이 작성할 필요는 없습니다. Java 및 C ++에서는 모든 방문 가능한 클래스에서 accept 메소드를 작성해야하지만 Python에서는 Visitable과 같은 믹스 인 클래스를 통해 해당 기능을 상속 할 수 있습니다.

class Visitable(object):
    def accept(self, visitor):
        visit = getattr(visitor, 'visit' + self.__class__.__name__)
        return visit(self)
...

class On(Visitable):
    ''' exactly like above '''

class Off(Visitable):
    ''' exactly like above '''

class SwitchStatePrinter(object): # Visitor
    def visitOn(self, switch):
         print 'the switch is on'
    def visitOff(self, switch):
         print 'the switch is off'

class SwitchAllOff(object): # Visitor
    def visitOn(self, switch):
         switch.switch()
    def visitOff(self, switch):
         pass
...
print_state = SwitchStatePrinter()
turn_em_off = SwitchAllOff()
for each in my_switches:
    each.accept(print_state)
    each.accept(turn_em_off)

정적 언어에서 패턴의 적용을 요구하는 많은 상황은 파이썬에서 그렇게 많이하지 않습니다. 고차 함수 (데코레이터, 함수 팩토리) 또는 메타 클래스와 같은 다른 기법으로 많은 것을 해결할 수 있습니다.


나는 당신의 대답이 내가 방금 물었던 질문에 대부분 부합한다는 것을 알고 있습니다 : 파이썬 에서 팩토리를 구현하기 위해 덮어 쓰는__class__ 것이 좋은 생각입니까?
rds
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.