2010-03-25 4 views
14

PRISM/MVVM/WPF 응용 프로그램을 작성하고 있습니다. LOB 응용 프로그램이므로 복잡한 규칙이 많이 있습니다. 보기 모델이 부풀어 오르기 시작했다는 것을 알았습니다. 두 가지 주요 쟁점이 있습니다.리팩터링 Bloated ViewModel

하나는 MVVM을 유지하는 것입니다. VM VM에 여러 속성을 추가하는 것과 같은 많은 일을하고 있습니다. 뷰는 이러한 속성에 바인딩되어 특정 정보를 보는 것과 같은 느낌을 추적합니다. 예를 들어, VM에서 장시간 실행중인 프로세스의 상태를 추적하는 부울 (Boolean)은 장시간 실행되는 프로세스가 작동하는 동안 뷰에서 일부 컨트롤을 비활성화 할 수 있습니다. 이 문제는 첨부 된 동작으로 해결할 수 있다고 읽었습니다. 나는 더 자세히 살펴볼 것입니다. 온라인에서 볼 수있는 MVVM 애플리케이션의 예에서는 과도하게 단순화 되었기 때문에 큰 문제는 아닙니다.

다른 문제는 내 VM의 명령 수입니다. 바로 지금 네 가지 명령이 있습니다. Josh Smith의 RelayCommand (기본적으로 PRISM에서는 DelegateCommand)를 사용하여 VM의 명령을 정의하므로 모든 비즈니스 로직이 VM에 존재합니다. 각 명령을 별도의 작업 단위로 이동하는 것을 고려했습니다. 이 작업을 수행하는 가장 좋은 방법은 확실하지 않습니다.

VM을 깨끗하게 유지하기 위해 어떤 패턴을 사용하고 있습니까? 나는 이미 "당신의 견해와 VM이 너무 복잡해서 많은 뷰/VM으로 깨뜨려야 만합니다"라고 응답 할 수 있습니다. Ux 관점에서 볼 때 너무 복잡하지는 않습니다. 두 개의 버튼, 콤보 박스 및 목록 상자가 있습니다. 또한, 논리적 인 관점에서, 그것은 하나의 응집 된 영역입니다. 그런 말로, 나는 다른 사람들이 이런 유형의 문제를 어떻게 다루고 있는지에 대해 매우 관심이있다.

입력 해 주셔서 감사합니다.

+1

어리석은 논평, 그러나 나는 저항 할 수 없다 : "무엇이 잘못 되었습니까?" 그것은 삶의 방식, 소프트웨어 개발의 한 방법입니다 ;-) –

+0

큰 질문입니다. 내 WPF 뷰 모델은 MVVM을 제대로 할 때 WPF의 한계를 극복하기 위해 해킹으로 가득 차 있습니다. 이 중 대부분은 WinForms MVP 앱에서 사소한 것입니다. – Damien

+0

MVPVM을 체크 아웃 할 수 있습니다. 기본적으로 VM을 분할하여 VM이 데이터 바인딩 만 처리하고 Presenter가 명령을 처리합니다. 나는 명령 바인딩의 편리 성을 어떻게 잃어 버리는 지 맘에 들지 않지만 깨끗한 VM을 위해 만들어 준다. – bygrace

답변

4

나는 당신의 고통을 느낍니다. MVVM 앱에서 작업 할 때 이러한 질문을 많이 다루고 있습니다. 요즘 나는 당신이 한 것처럼 다른 사람들의 의견을 얻기 위해 빨래 목록을 게시 할 것입니다.

필자는 ViewModel 기본 클래스에서 "부풀어 오름"에 대해 많이 염려하지만, 구체적인 ViewModel 하위 클래스에서는 그리 걱정하지 않습니다. 2-3 개의 ViewModel에 의해 사용되는 의존성을 기본 클래스에 던지기를 원하지만 종종 피해야합니다.

당신의 생각이 부풀어 오르는 것을 나는 추측 할 수 없지만, VM에서 처리되는 "busy"속성이나 명령이 좋지 않다고 나는 말할 수 있습니다. 한 가지 고려해야 할 것은 ViewModel이 한 번에 여러 가지 작업을 수행 할 수 있는지 여부입니다. 그렇다면, 앞으로 나아가 그것을 깨뜨리는 방법에 대해 생각해보십시오. 개인적으로 실제로 본적이 없지만, 단 하나의 응집력있는 뷰와 몇 개의 ViewModels가있을 수 있습니다.

명령이 길거나 다른 대상에서 실행할 수있는 경우 명령 자체 실행 단위를 만드는 것이 좋습니다. 그러나 나중에이 방법을 사용하는 사람을 혼동하지 않도록이 방법과 일관되게하는 것이 가장 좋습니다. 예를 들어 SaveCustomerCommand 클래스가 약 10 줄의 코드라면 RelayCommand를 다른 모든 것에 사용하고 싶지 않을 것입니다.

이런 종류의 물건에 대한 엄격하고 빠른 규칙이 있다면 좋겠지 만 프레임 워크와 패턴은 아직 진화 단계에 있다고 생각합니다.

+0

답변 해 주셔서 감사합니다. Josh. 그래, 나는 그 틀이 아직 젊다는 것에 동의한다. 블로 팅 = 하나 이상의 변화하는 방식으로 SRP를 위반합니다. – Noel

+0

오, 그런 경우에 ... 행운을 빈다! :) SRP가 완전히 과대 평가 된 것 같습니다. 현실 세계에서는 기본적으로 클래스 당 하나의 메소드를 규정합니다. 명령 클래스에서는 괜찮을 지 모르지만, 모델 및 뷰 모델에 적용 할 때 팔리지는 않습니다. – Josh

0

ViewModel의 특성을 알지 못하면 팽창이 어디서 오는지 말할 수 없습니다. 모델을 쿼리하는 데 너무 많은 행처럼 UI와 관련이 없을 수 있습니다. 또는 트리거 또는 기타 기능을 통해 UI에서 더 잘 구현되는 UI 기능 일 수 있습니다.

ViewModel에 대해 자세히 설명해 주시겠습니까?

편집 의견을 기반으로합니다.

SaveCustomer 및 DeleteCustomer는 모델이나 서비스 메소드처럼 들리므로 어떤 종류의 지속성 레이어에 넣을 수 있습니다.

고객 비디오 업로드/다운로드 : 다시 WebService에 넣고 ViewModel 명령을 호출하도록 ViewModel에만 해당되는 ViewModel은 아닙니다 (다른 ViewModel에서이 작업을 수행 할 수도 있습니다).

일반적으로 공통된 코드 (여러 개의 ViewModels가 사용하기를 원할 수도 있음)를 서비스에 넣은 다음 IOC에 서비스를 던질 가치가 있습니다. 그렇게하면 ViewModel은보기에서 모델 또는 서비스에 대한 정보의 가벼운 "감독자"가됩니다.

+0

bloat은 위에서 설명한대로 4 개의 명령과 특정보기 속성에서옵니다.내 질문은 추상적 인 것입니다 : 사람들이 논리를 ViewModel 외부의 작업 단위로 추상화하기 위해 사용하는 패턴은 무엇입니까? 뷰와 VM 특정 로직 사이에 선을 그려야합니까? 예를 들어 SaveCustomer, DeleteCustomer, 고객 비디오 업로드 (장기 실행), 고객 비디오 다운로드 (장기 실행)의 4 가지 명령을 사용합시다. 뷰는 장시간 실행되는 비디오 명령의 상태를 알아야합니다. – Noel

+0

응답에 감사드립니다. – Noel

+0

RelayCommands는 응용 프로그램의 다른 레이어에서 다른 구성 요소와 서비스를 호출하지만 내 VM에서 정의 된 RelayCommands가 있어야 내보기를 바인딩 할 수 있습니다. 따라서 고객 비디오 다운로드 명령의 경우 VM은 웹 서비스를 호출하여 비디오를 가져오고 응답에 바이트 수준의 조작을 한 다음 다른 구성 요소를 사용하여 비디오를 엽니 다. 아마도 RelayCommand/DelegateCommand 로직을 다른 클래스로 추출 할 수 있고 RelayCommands를 새로운 클래스에 위임하는 얇은 베니어로 만들 수 있습니다. – Noel

0

나는 이것에 대해 두 가지 주된 생각을 가지고있다. 그러나 YMMV.

먼저 VM의 구현 코드를 기본적으로 작업을 수행하는 클래스 인 '서비스'로 옮깁니다. 이것은 예를 들어 save, delete, update 메소드의 구현을 가지는 'customerService'클래스 일 수 있으며, RelayCommand 구현은 서비스를 호출하여 조치를 수행하고 적절한 뷰 속성을 업데이트합니다.

예제에서는 RelayCommand가 진행률 표시 줄의 가시성에 바인딩 된 "ShowProgressBar"속성 값을 설정할 수 있습니다. 그런 다음 서비스의 저장 함수를 호출하고 완료되면 (비동기 btw이어야 함) 다시 "ShowProgressBar"를 업데이트해야합니다. 이런 방식으로 ViewModel은 핵심 애플리케이션 로직과 독립적으로 View의 상태를 제어합니다.

두 번째로 나는 사용하고있는 기본 viewmodel을 살펴보고 모든 viewmodels에 공통 인 구성 요소 만 추가하는 등 가능한 한 간단하게 유지하려고합니다. 그런 다음 다른 기본 뷰 모델 또는 인터페이스를 적절하게 만들 수 있습니다. 예를 들어 모든 뷰 모델에서 페이지의 진행률 막대에 바인딩 할 수있는 ShowProgressBar 속성이 표시되거나 진행률 막대가 필요한 페이지에서 상속/구현하는 ProgressViewModelBase 또는 IAllowProgress를 만들 수 있습니다.

보기 자체에는 가능한 적은 코드가 있어야합니다. 코드 숨김을 0으로 설정해야합니다 (불행히도 코드 숨김에서만 수행 할 수있는 작업이 있지만).

내가 알아 낸 한 가지 사실은 복잡한 관점 모델의 인스턴스화가 성능면에서 비용이 많이들 수 있습니다. 특히 릴레이 명령과 이벤트 수집기 소스/수신기를 등록하는 경우 비효율적이어서 기본 뷰 모델을 매우 슬림하게 유지해야합니다. 이는 ViewModelCollections를 사용하여 Model 객체의 목록을 표시하고 ViewModel이 UI 작성 스레드에서 발생하는 경우 (ViewModel이 View 작성시 인스턴스화 된 경우)에 특히 중요합니다.