2009-09-18 5 views
2

이것은 매우 기본적인 것이지만 일종의 일반적인 문제이므로 사람들의 생각을 듣고 싶습니다. 나는 기존의 MSI 파일을 가져 와서 몇 가지 표준 수정으로 업데이트하고 새로운 MSI 파일 (변경 사항이있는 이전 파일의 복제본)을 작성해야하는 상황이 있습니다.클래스 디자인 : 파일 변환 논리 및 클래스 디자인

필자는 원래의 MSI에 대한 몇 가지 공개 방법과 기본 입력 경로를 사용하여이 글을 쓰기 시작했습니다. 그들이 사용할 수 있도록 대신 생성자의 일부로서 모든 변환 로직을 넣어

var custom = CustomPackage(sourcemsipath); 
custom.Duplicate(targetmsipath); 
custom.Upgrade(); 
custom.Save(); 
custom.WriteSmsXmlFile(targetxmlpath); 

이 더 잘 될 것이다 : 것은이 제대로 작동하려면, 통화의 엄격한 경로는 발신자에서 다음되어야한다 공개 방법으로? ,

var custom = CustomPackage(sourcemsipath, targetmsipath); // saves converted msi 
custom.WriteSmsXmlFile(targetxmlpath); // saves optional xml for sms 

생성자는 다음 직접 MSI 파일을 복제 할를 업그레이드하고 목표 위치에 저장 : (순서대로 호출 측이 "올바른 순서"가 무엇인지 알고 있어야하는 것을 피하기 위해). "WriteSmsXmlFile"은 항상 필요하지 않기 때문에 여전히 public 메서드입니다.

개인적으로 저는 실제로 생성자를 "do stuff"하고 싶지 않습니다. public 메서드를 호출 할 수있는 것을 선호하지만 잘못된 것으로 보입니다. 호출자가 적절한 호출 순서를 알아야한다고 가정하십시오.

대안은 파일을 먼저 복제 한 다음 복제 된 파일을 생성자에 전달하는 것이지만 클래스 자체에서이 작업을 수행하는 것이 좋습니다.

어쩌면 내가 뒤를 모두 가지고 두 클래스가 필요합니다. SourcePackage, TargetPackage 그리고 SourcePackage를 TargetPackage의 생성자로 전달 하시겠습니까?

답변

1

그것은 나일지도 모르지만 이러한 모든 일을하는 생성자의 생각은 나를 떨게 만든다. 그러나이 모든 않는 정적 방법을 제공하지 이유 :

public class CustomPackage 
{ 

    private CustomPackage(String sourcePath) 
    { 
     ... 
    } 

    public static CustomPackage Create(String sourcePath, String targetPath) 
    { 
     var custom = CustomPackage(sourcePath); 
     custom.Duplicate(targetPath); 
     custom.Upgrade(); 
     custom.Save(); 
     return custom; 
    } 
} 

이 방법의 실제 장점은 (변환 과정이 실제로 성공하지 않는 한 CustomPackage의 인스턴스를 제공 할 필요가 없습니다 것입니다 옵션 부품의 안전).

C#으로 편집이 공장에있어서조차 Factory Pattern에 따라 "참"공장으로 (대리인을 이용하여) 이용 될 수

public interface ICustomizedPackage 
{ 
    ... 
} 

public class CustomPackage: ICustomizedPackage 
{ 
    ... 
} 

public class Consumer 
{ 
    public delegate ICustomizedPackage Factory(String,String); 

    private Factory factory; 

    public Consumer(Factory factory) 
    { 
     this.factory = factory; 
    } 

    private ICustomizedPackage CreatePackage() 
    { 
     return factory.Invoke(..., ...); 
    } 

    ... 
} 

이상 :

new Consumer(CustomPackage.Create); 
+0

이것은 "공장 조명"과 같은 흥미롭고 일반적인 적용 방법입니다. –

+0

그래서 당신은 말할 수 있습니다. 특히, C#에서 최소한 Create() 메소드를 전달하기 위해서는 위임자와 함께 이것을 사용하십시오. – Dirk

+0

감사합니다. Dirk, 귀하의 회신을 수락으로 설정했습니다. 그러나 내가 upvote를 클릭했을 때 실제로 투표를 감소 시켰는가 ?? 다시 클릭하려고하면 투표가 너무 오래되어 변경 될 수 없다고 말합니다. 나는 이미이 대답을 미리 upvoted해야하고, 다시 클릭하면 되돌아 왔음에 틀림 없다. 기묘한. 어쨌든, 철저한 답변 주셔서 감사합니다. –

2

나는 첫 번째 생각과 함께 갈 것입니다 : 변환 논리를 모두 한 곳에 모으십시오. 해당 시퀀스를 사용자에게 노출 할 이유는 없습니다.

덧붙여서 나는 생성자에 액션을 넣지 않는 것에 동의합니다. 아마 생성자에서이 작업을 수행하지 않고 대신 별도의 변환기 메서드로 작업을 수행하지만 개인적인 취향입니다.

1

이러한 상황에서 나는 전형적으로 다음과 같은 디자인을 사용한다 :

var task = new Task(src, dst); // required params goes to constructor 
task.Progress = ProgressHandler; // optional params setup 
task.Run(); 
1

생성자가 단순히 객체를 초기화하는 것보다 더 많은 작업을해서는 안된다고 생각하는 것은 맞습니다.당신이 필요로하는 Duplicate, UpgradeSave하여 작업의 올바른 순서를 알 수있는 호출자에 대한 필요성을 제거하는 호출을 래핑하는 Convert(targetmsipath) 기능처럼 같은 시간에 밖으로 논리를 유지하면서

은 나에게 소리 생성자의.

targetxmlpath 매개 변수를 포함하도록 오버로드하여이 매개 변수를 제공하면 WriteSmsXmlFile 기능을 호출 할 수도 있습니다. 그런 식으로 모든 관련 작업은 호출자 측에서 동일한 함수에서 호출되며 작업 순서는 항상 정확합니다.

+1

+1 : 올바른 순서로 일을 처리하는 또 다른 공용 기능에는 아무런 문제가 없습니다. –

+0

생성자에 지정된 원본 경로에 대해 저장을해서는 안되지만 여기에 설명 된 것처럼 public 메서드에 대해 출력 경로를 지정하면됩니다. –

0

나는 서비스 지향적 인 방법과 객체 지향적 인 방법이 있다고 생각한다.

불변의 데이터 전송 개체 (엔티티)를 따라 전달하는 일련의 필터를 만드는 것이 서비스 지향적 인 방법입니다.

var service1 = new Msi1Service(); 
var msi1 = service1.ReadFromFile(sourceMsiPath); 
var service2 = new MsiCustomService(); 
var msi2 = service2.Convert(msi1); 
service2.WriteToFile(msi2, targetMsiPath); 
service2.WriteSmsXmlFile(msi2, targetXmlPath); 

decorator pattern을 사용할 수 있습니다.

var decoratedMsi = new CustomMsiDecorator(new MsiFile(sourceMsiPath)); 
decoratedMsi.WriteToFile(targetMsiPath); 
decoratedMsi.WriteSmsXmlFile(targetXmlPath);