2010-04-22 4 views
3

구성 파일과 같은 외부 리소스의 이름과 같은 매개 변수로 일회 초기화가 필요한 특정 클래스에서 디자인 문제가 다시 발생합니다.C# 정적 생성자 디자인 문제 - 매개 변수를 지정해야합니다.

예를 들어 응용 프로그램 전반의 로깅, 구성 및 일반적인 도우미 메서드를 제공하는 corelib 프로젝트가 있습니다. 이 객체는 정적 생성자를 사용하여 자체를 초기화 할 수 있지만 자체에서 찾을 수없는 구성 파일에 액세스해야합니다.

나는 솔루션의 몇 가지를 볼 수 있지만이 둘은 아주 잘하지 않는 것 :

1) 매개 변수가있는 생성자를 사용합니다. 하지만 corelib 기능을 필요로하는 각 객체는 config 파일의 이름을 알아야하므로 응용 프로그램을 통과해야합니다. 또한 corelib을 싱글 톤으로 구현 한 경우 config 파일을 GetInstance 메서드의 매개 변수로 전달해야합니다.이 메서드는 GetInstance 메서드에서도 올바르지 않습니다.

2) 구성 파일이나 기타 외부 매개 변수를 전달하는 정적 속성 또는 메서드를 만듭니다.

나는 일종의 후자의 방법을 사용하고 생성자의 구성 파일을 통과하는 내부 클래스를 초기화하는 Load 메서드를 만들었습니다. 그런 다음이 내부 클래스는 MyCoreLib이라는 공용 속성을 통해 노출됩니다.

public static class CoreLib 
{ 
    private static MyCoreLib myCoreLib; 

    public static void Load(string configFile) 
    { 
     myCoreLib = new MyCoreLib(configFile); 
    } 

    public static MyCoreLib MyCoreLib 
    { 
     get { return myCoreLib; } 
    } 

    public class MyCoreLib 
    { 
     private string configFile; 

     public MyCoreLib(string configFile) 
     { 
      this.configFile = configFile; 
     } 

     public void DoSomething() 
     { 
     } 
    } 
} 

저는 여전히 행복하지 않습니다. 내부 클래스는 load 메소드를 호출 할 때까지 초기화되지 않으므로 MyCoreLib에 액세스 할 필요가있는 모든 위치를 고려해야합니다. 또한 누군가가 load 메소드를 다시 호출하는 것을 막을 수는 없습니다.

다른 패턴이나 아이디어는 어떻게 수행합니까?

답변

1

에서 설정 한 최초의 두통 후이를 탐구하지 않았다 이것을 저장할 일반적인 장소. 라이브러리 어셈블리에서 config 섹션을 정의하고 app.config를 proceess하여이를 참조함으로써 별도의 어셈블리 인 경우에도 app.config를 사용할 수 있습니다. 또는 appSettings에 일반 설정을 추가하고 강력한 입력 설정을 사용하지 않고 참조 할 수 있습니다. 값이 사용자 인 경우 격리 된 저장소를 사용할 수 있습니다. 마지막으로 설치시 레지스트리의 잘 알려진 위치에 넣을 수 있습니다. 코드

다음은 당신의 도움 덕분에 모든 사람을

public interface ICoreLib 
    { 
     void SomeMethod(); 
    } 
    public static class CoreLibManager 
    { 
     private static ICoreLib coreLib; 
     private static volatile bool initialized; 
     private static readonly object lockObject = new object(); 
     public static ICoreLib CoreLib 
     { 
      get 
      { 
       Inititialize(); 
       return coreLib; 
      } 
     } 

     /// <summary> 
     /// The inititialize. 
     /// </summary> 
     private static void Inititialize() 
     { 
      if (initialized) 
      { 
       lock (lockObject) 
       { 
        if (!initialized) 
        { 
         string configFile = // Fech from common location 
         coreLib = new MyCoreLib(configFile); 
         initialized = true; 
        } 
       } 
      } 
     } 

     /// <summary> 
     /// The my core lib. 
     /// </summary> 
     private class MyCoreLib : ICoreLib 
     { 
      public MyCoreLib(string configPath) 
      { 
      } 
      public void SomeMethod() 
      { 
      } 
     } 
    } 
+0

감사합니다. csaam, 코드 캡슐화의 더 나은 예를 제공했습니다. 이러한 아이디어를 내놓을 것입니다. 저는 OOP에 대해 아직 조금 익숙합니다. 아직 내부 MyCoreLib 클래스를 숨길 수 있었지만 CoreLib 속성을 통해 객체를 노출 한 이유는 무엇입니까? –

+0

불행히도 이것은 여전히 ​​런타임까지 외부 리소스 파일의 위치를 ​​알 수 없다는 사실로 내 문제를 해결하지 못합니다. 그러나이 예제를 통해 우리는 app/user 설정을 사용하여이를 클래스 프로젝트 내에 포함 시키려고 할 것입니다. –

+0

-OFF TOPIC- 앱 설정에 대해 마음에 들지 않는 것은 설치 프로그램 프로젝트와 동기화되지 않는다는 것입니다. 따라서 WinForms 앱을 설치하면 사용자 생성 파일을 \ Users 또는 AppData 또는 사용자 정의 폴더 등 다양한 위치에 배치 할 수 있습니다. 설치 프로그램이 완료된 후이 위치를 앱으로 가져 오는 것은 상당히 어렵습니다. 이것이 내가 시작시 위치를 결정한 후 CoreLib 관리자가 CoreLib를 처리 할 수 ​​있다고 가정하기보다는 위치를 전달하는 코드를 작성하려고하는 이유입니다. 매우 까다 롭지 만이 시나리오는 꽤 자주 발생해야합니까? –

0

클래스를 싱글 톤으로 만들 수 있으므로 생성자 매개 변수를 허용하면서 클래스 인스턴스를 하나만 확보 할 수 있습니다.

+0

그가 게시 한 코드 샘플은 기본적으로 싱글 톤입니다. 더 구체적 : 공장에서 싱글 톤을 생성합니다. – Foxfire

0

대체 방법이 많지 않습니다.

은 어느 당신은 내가 주위에 문자열을 전달하지만,() 비 정적 CoreLib 콘크리트를 만들고 그 주위를 통과하지 않는 게 좋을 경우에 (주위에 물건을 전달하거나 당신은 당신이 무엇을 제안 할.

잊지 마세요 MyCoreLib의 생성자를 숨기기 위해서 현재 의도하지 않은 public입니다.

+0

예, MyCoreLib을 다른 곳에서 인스턴스화하는 것을 중지하는 것이 유용하지만 생성자를 private으로 설정하면 부모 클래스의 정적로드 메서드가 완전히 중지되어 MyCoreLib 인스턴스가 생성되지 않습니다. –

+0

예. 내부가 좋다. – Foxfire

1

초기화가 필요하고 초기화 (예 : 구성 파일)를 완료하기 위해 외부 입력이 필요하면이 경우 로드 또는 초기화를 호출하여 전역 상태를 초기화해야하는 입력을 알고있는 외부 코드가 붙어 있습니다.이 문제를 해결할 방법은 없습니다.

그러나 올바르게 관찰 한 문제는 제대로 초기화하지 않으면 누구든지 전역 상태를 사용하려고 시도 할 수 있다는 것입니다.이 상태로 노출되는 것이 단점입니다. 이 문제를 해결하는 방법은 전역 라이브러리의 모든 상태 저장 부분을 인스턴스 클래스로 리팩토링하고 응용 프로그램을 통해 해당 인스턴스에 대한 참조를 전달하는 것입니다. 생성 및 초기화 시점을 제어하기 때문에 전달하기 전에 유효한 상태인지 확인할 수 있습니다. 당신은 당신이 겪고있는 더 나은 단열을 위해 전지구 적 국가의 편리함을 상쇄합니다.

1

.net 구성 시스템을 사용하여이 작업을 수행 할 수 있습니다. 가장 간단한 방법은 web.config 파일 또는 appname.exe.config 파일에서 <appsettings> 요소를 사용하는 것입니다.사용 :

ConfigurationManager.AppSettings["property_name"] 

속성에 액세스하려면. 코드가 웹 컨텍스트에서 실행 되든 Windows 응용 프로그램으로 실행 되든 구성 시스템은 구성 파일을 찾고 필요한 값을로드합니다.

또한 형태 보증 된 설정 값 및 계층 적 데이터와 더 복잡한 시스템을 구축 할 수 있지만, 내 요구는 아주 간단했다, 그래서 나는 당신이 필요합니다 :)

0

더 확인을 encapsulted된다. 필자는 CoreLib 프로젝트를 리팩터링하고 별도의 프로젝트로 구성 처리를 분해했습니다. 이제 우리는 설정 관리를위한 솔루션 차원의 공유 클래스를 갖게되었습니다. 클래스는 정적 속성 인 ConfigFile을 통해 노출되는 사용자 설정을 통해 자체적으로 처리 할 수 ​​있습니다. 이 속성은 사용자가 일부 구성 대화 상자를 통해 변경된 경우 수정 된 파일 위치도 유지합니다. 또한 설정 파일이 변경되면 초기화 된 플래그가 재설정됩니다.

public interface IConfig 
{ 
    void SomeMethod(); 
} 

public static class ConfigurationManager 
{ 
    private static IConfig config; 
    private static volatile bool initialized; 
    private static readonly object lockObject = new object(); 

    public static string ConfigFile 
    { 
     get { return Properties.Settings.Default.ConfigFile; } 
     set 
     { 
      if (Properties.Settings.Default.ConfigFile == value) return; 

      lock (lockObject) 
      { 
       Properties.Settings.Default.Save(); 
       initialized = false; 
      } 
     } 
    } 

    public static IConfig Config 
    { 
     get 
     { 
      Inititialize(); 
      return config; 
     } 
    } 

    private static void Inititialize() 
    { 
     lock (lockObject) 
     { 
      if (initialized) return; 

      config = new Configuration(Properties.Settings.Default.ConfigFile); 
      initialized = true; 
     } 
    } 
} 

internal class Configuration : IConfig 
{ 
    public ClientConfig(string configFile) 
    { 
     // Parse & validate config file 
    } 

    public void SomeMethod() 
    { 
    } 
} 

그래서 이제 시작에 우리는 먼저 관리자의 구성 속성을 통해 구성 인스턴스에 액세스하려고 시도의 지속 ConfigFile 대 설정을 확인합니다. 파싱 ​​예외는 여기에서 처리되어 그에 따라 처리 될 수 있습니다. IConfig의 메소드에 대한 예외를 처리하는 것은 개발자의 몫입니다.

if (!System.IO.File.Exists(ConfigurationManager.ConfigFile)) 
{ 
    // Display config file locator dialog 
    ConfigurationManager.ConfigFile = someDialog.FileName; 
} 

try 
{ 
    IConfig config = ConfigurationManager.Config; 
} 
catch 
{ 
    // Error parsing config file 
} 
관련 문제