2014-01-29 3 views
1

이것은 내 첫 번째 게시물입니다.vb.net 인보이스 및 상속 디자인

저는 우리 소프트웨어를위한 새로운 모듈을 디자인하는 것에 대해 조언하고 싶습니다. 그것은 vb6로 작성되었으며 vb.net에서 다시 작성하고 싶습니다. 그래서 그것을 리팩토링하고 싶습니다.

다음을 수행합니다.

OpenOffice 문서 용 템플릿이 많이 있습니다. (약 300) 각 하나는 데이터베이스에 있으며 입력으로 제공되는 고유 한 식별자를가집니다.

이 번호로 달기 문서를 만들고 싶습니다. 예 : calc 또는 writer 또는 나중에 다른 것. 그런 다음 doc [template_num] 또는 sth라는 메서드를 호출합니다.

메소드 호출에 대해 읽었습니다. 나는 이것을 숫자로 동적으로 메소드를 호출하는 좋은 방법이라고 생각한다. 이것을 시도했다. 나는 그것이 어떻게 작동하는지 지금 이해한다고 생각한다. 하지만 문서 유형을 처리하는 방법을 모른다. 모든 calc 문서가 처음부터 동일하게 만들어져 코드의 큰 부분을 재사용하고 싶습니다. 그러나 세포를 채우는 것은 약간 다릅니다.

나는 invoke를 사용하여 메소드 호출을 상속하고 수행하는 방법을 모른다.

누군가 나를 설명 할 수있는 약간의 코드 스 니프를 가지고있을 수 있습니다. 또는이 문제를 해결하는 방법에 대한 다른 좋은 아이디어.

이에 대한 새로운 생각에 감사드립니다.

+0

템플릿의 ID는 항상 정수입니까? 일치하는 경우 ID 번호 순차에 간격이 있습니까? –

+0

지금까지 시도한 내용의 샘플을 제공 할 수 있습니까? – StingyJack

+0

예. ID는 정수이고 순차적입니다. – Dschon

답변

0

당신은, 물론, 단지 다음과 같이 거대한 Select Case 블록 수 :

Public Sub CreateDoc(templateNum As Integer) 
    Select Case templateNum 
     Case 1 
      CreateDoc1() 
     Case 2 
      CreateDoc2() 
     Case 3 
      CreateDoc3() 
    End Select 
End Sub 

당신은 아마 더 나은, 더 간단한 방법이 될 것입니다 경우 문 상당히 적은 수 있던 경우에. 그러나 설명대로 많은 다양한 ID를 찾을 수 있다면 실용적이지 않으며 큰 Select Case 블록이 없으면 올바른 방법을 호출하고자하는 바램에 감사드립니다.

그러나 내가 들어가기 전에 다른 옵션을 주어야한다고 생각합니다. 아마 당신은 그 많은 다른 방법을 가질 필요가 없을 것입니다. 예를 들어, 템플리트 ID의 절반은 실제로 모두 동일한 방식으로 처리되어야하며, 유일한 차이점은 템플리트 파일 이름이 달라야한다는 것입니다. 그렇다면 Select Case 블록이 그만큼 클 필요가 없다고 생각할 수 있습니다. 예를 들면 다음과 같습니다.

Public Sub CreateDoc(templateNum As Integer) 
    Select Case templateNum 
     Case 1 To 100 
      CreateWriterDoc(GetTemplateFilePath(templateNum)) 
     Case 101 To 200 
      CreateCalcDoc(GetTemplateFilePath(templateNum)) 
    End Select 
End Sub 

Private Sub CreateWriterDoc(templateFilePath As String) 
    ' Launch Writer with given template file 
End Sub 

Private Sub CreateCalcDoc(templateFilePath As String) 
    ' Launch Calc with given template file 
End Sub 

Private Function GetTemplateFilePath(templateNum As Integer) As String 
    ' Retrieve template file path for given ID 
    ' (from DB, Array, List, Dictionary, etc.) and return it 
End Sub 

나에게 이것은 훨씬 간단한 해결책처럼 보입니다. 그렇지 않은 경우 - 실제로 각기 다른 템플릿 ID에 대해 실행해야하는 완전히 다른 논리가있는 경우 여러 가지 방법으로 수행 할 수 있습니다. 첫 번째 옵션은 각 ID를 호출 할 적절한 메서드를 가리키는 대리자 목록을 만드는 것입니다. 예를 들어, 다음과 같이 배열에 저장할 수 :

Dim createDocDelegates() As Action = 
    { 
     AddressOf CreateDoc1, 
     AddressOf CreateDoc2, 
     AddressOf CreateDoc3 
    } 

그래서 지금, 그 세 대표가 배열에 (0 ~ 2) 번호에 의해 색인되어있다.이 같은 번호로 그들을 호출 할 수 있습니다 : 다음

Dim createDocDelegates As New Dictionary(Of Integer, Action)() 
createDocDelegates.Add(1, AddressOf CreateDoc1) 
createDocDelegates.Add(7, AddressOf CreateDoc7) 
createDocDelegates.Add(20, AddressOf CreateDoc20) 

을 수행 할 수 있습니다 : 당신의 ID 년대 순차적하지 않은 경우

createDocDelegates(1).Invoke() ' Calls CreateDoc2 

또는,이 같이 대신, Dictionary(Of Integer, Action) 사용할 수 있습니다 이 같은 ID 하나를 호출

createDocDelegates(7).Invoke() ' Calls CreateDoc7 

또 다른 옵션은 다음과 같이 문서를 생성하는 개체에 대한 Interface을 생성하는 것입니다 :

Public Interface IDocCreator 
    Sub CreateDoc() 
End Interface 

그런 다음 각각의 동일한 인터페이스를 구현하는 각 유형의 템플릿에 대해 별도의 클래스를 구현할 수 있습니다. 예를 들어 :

Public Class Doc1Creator 
    Implements IDocCreator 
    Public Sub CreateDoc() Implements IDocCreator 
     ' Do work 
    End Sub 
End Class 

Public Class Doc2Creator 
    Implements IDocCreator 
    Public Sub CreateDoc() Implements IDocCreator 
     ' Do different work 
    End Sub 
End Class 

그런 다음 다음과 같이 해당 개체의 목록을 만들 수 있습니다

Dim docCreators() As IDocCreator = 
    { 
     New DocCreator1(), 
     New DocCreator2() 
    } 

또는 :

Dim docCreators As New Dictionary(Of Integer, IDocCreator)() 
docCreators.Add(1, New DocCreator1()) 
docCreators.Add(7, New DocCreator7()) 
docCreators.Add(20, New DocCreator7()) 

를 그리고이 같은 하나를 호출 할 수 있습니다

docCreators(1).CreateDoc() 

IDocCreator appr oach는 Delegate 접근 방식과 매우 유사합니다. 그것을하는 옳고 그른 방법도 아닙니다. 그것은 당신의 스타일, 당신이 편안하고 요구 사항에 따라 다릅니다. IDocCreator 접근 방식의 가장 큰 장점은 앞으로 더 많은 속성과 메서드를 쉽게 추가 할 수 있다는 것입니다. 예를 들어, 각 템플리트에 대해 사용자에게 친숙하고 설명이 담긴 이름을 어딘가에 저장하려고한다고 가정 해보십시오. IDocCreator 인터페이스에 ReadOnly Property Name As String 속성을 추가하는 것은 매우 쉽지만 위임자 목록 경로를 사용하면 더 어렵고 어색 할 것입니다.

그러나 위의 예에서 모든 방법이나 대리인 목록을 추가해야합니다. 따라서 거대한 Select Case 블록보다 약간 못 생겨도 여전히 충분하지 않을 수 있습니다. 그렇다면 당신이 사용해야하는 기술은 Reflection입니다. System.Reflection 네임 스페이스에는 많은 리플렉션 관련 기능이 포함되어 있습니다. 리플렉션을 사용하면 코드의 일부에 동적으로 액세스하고 호출 할 수 있습니다. 예를 들어, 리플렉션을 사용하여 주어진 클래스에 의해 정의 된 모든 특성 또는 메소드 목록을 얻을 수 있습니다. 또는 리플렉션을 사용하여 어셈블리에서 정의한 형식 목록을 가져올 수 있습니다. 리플렉션을 사용하면 문자열 이름을 기준으로 메서드를 가져온 다음 메서드를 호출 할 수 있습니다. 현재 개체의 "CreateDoc1" 메소드를 호출 할 경우에 따라서, 예를 들어, 당신은 이런 식으로 그것을 할 수 :

Me.GetType().GetMethod("CreateDoc1").Invoke(Me, {}) 

당신은 문자열의 이름을 호출하기 때문에, 당신은 연결을 통해 메소드 이름을 만들 수 : 대신 메소드의 이름을 사용하는 반사 방법을 사용하려는 경우

Dim methodName As String = "CreateDoc" & templateNum.ToString() 
Me.GetType().GetMethod(methodName).Invoke(Me, {}) 

그러나, 그런 식으로, 그것은 청소기 될 것이다, 내 의견으로는, 각 방법에 태그를 사용자 지정 특성을 사용하는 .예를 들어, 당신이 이런 식으로 당신의 방법을 장식 할 수있는 속성 클래스 만들 수 있습니다 실행시

<CreateDocMethod(1)> 
Public Sub CreateDoc1() 
    ' ... 
End Sub 

다음을, 당신은 그 특정 속성과이 모든 방법을 찾기 위해 반사를 사용할 수 있습니다 오른쪽 하나를 호출합니다.

마지막으로 반영에 토론을 저장 한 이유는 효율적이지 않고 부서지기 쉬운 코드로 이어질 수 있기 때문입니다. 따라서 리플렉션을 최후의 수단으로 사용하는 것이 가장 좋습니다. 리플렉션에는 아무런 문제가 없습니다. 실제로 필요하다면,하지만 일반적으로, 리플렉션을 요구하지 않는 또 다른 합리적인 방법이 있다면, 아마도 다른 방식으로해야 할 것입니다.

+0

긴 코멘트에 대해 먼저 감사드립니다. – Dschon

+0

나는 그 반사 방식을 시도했고 또한 대의원들과 함께 약간의 테스트를했다. 그것은 나를 위해 모두 작동하지만 대리자 배열에 서브의 이름을 저장하지 않아도되기 때문에 메소드를 호출하는 것이 좀 더 동적이라고 생각했습니다. effiency에 대해 생각하지 않았다. 이제는 거대한 select case 블록으로 처리됩니다. 거의 모두 다르게 처리됩니다. – Dschon

+0

문제 없습니다. 기꺼이 도와주세요. 네, 상황에 대한 구체적인 사실 만 알면 최선의 해결책을 선택할 수 있습니다 :) 그래서 내가 생각할 수있는 모든 방법을 다루려고했습니다. 그런데 SO에 오신 것을 환영합니다! 앞으로 당신을 볼 수 있기를 바랍니다. –