2011-01-10 5 views
5

저는 지역화하고 국제화해야하는 웹 응용 프로그램을 만들고 있습니다. 의존성 주입 프레임 워크를 사용하여이 작업을 수행 할 수있었습니다.DI 프레임 워크를 사용하여 현지화 - 좋은 생각이십니까?

interface ILocalResources { 
    public string OkString { get; } 
    public string CancelString { get; } 
    public string WrongPasswordString { get; } 
    ... 
} 

을하고이 인터페이스, I 지원해야하는 각 언어에 대해 하나의 구현을 만듭니다의 내가 인터페이스 ILocalResources 선언 말한다 (이 예를 들어 C#을 사용을하지만 정말 중요하지)하자. 그런 다음 DI 프레임 워크를 정적 또는 동적으로 적절한 구현 (예 : 요청한 브라우저 기본 설정 언어 기반)을 인스턴스화하도록 설정합니다.

이런 종류의 DI 프레임 워크를 사용하면 안되는 이유가 있습니까? 어쨌든 내 웹 응용 프로그램에서 DI 프레임 워크를 사용하고 있다면 국제화에도 사용할 수 있습니까?

답변

2

기존 리소스 프레임 워크 (ASP.Net에 내장 된 리소스 프레임 워크)를 사용할 수없고 자신 만의 리소스 프레임 워크를 작성해야한다면 어느 시점에서 지역화 된 리소스를 제공하는 서비스를 노출해야한다고 가정합니다.

DI 프레임 워크는 서비스 인스턴스화를 처리하는 데 사용됩니다. 현지화 프레임 워크는 현지화를 제공하는 서비스를 노출합니다. 그 서비스가 프레임 워크에 의해 제공되어서는 안되는 이유는 무엇입니까?

DI를 목적으로 사용하지 않는 것은 여기에 "나는 CRM 응용 프로그램을 만들지 만 DI는 고객 관계 관리를 위해 설계되지 않았기 때문에 DI를 사용할 수 없습니다"라고 말하는 것과 같습니다.

그렇습니다. 이미 응용 프로그램의 나머지 부분에서 DI를 사용하고 있다면, IMO는 현지화를 처리하는 서비스에 IM을 사용하지 않는 것이 좋을 것입니다.

2

내가 볼 수있는 유일한 단점은 "리소스"를 업데이트 할 때 리소스가 포함 된 어셈블리를 다시 컴파일해야한다는 것입니다. 그리고 프로젝트에 따라,이 단점은 값 자체보다는 ResourceService를 해결하기위한 DI 프레임 워크 만 사용하는 것이 좋습니다.

6

DI 프레임 워크는 종속성 주입을 수행하기 위해 제작되었으며 현지화는 서비스 중 하나 일 수 있습니다. 따라서이 경우 DI 프레임 워크 IMO를 사용하는 이유는 없습니다. 입니다. 아마도 우리는 제공된 ILocalResources 인터페이스에 대해 논의하기 시작해야 할 것입니다. 컴파일 시간 지원에 호의적인데, 제공된 인터페이스가 도움이 될지 확신 할 수 없습니다. 인터페이스가 아마도 시스템에서 가장 많이 변경 될 유형이기 때문입니다. 그리고 그 인터페이스를 구현하는 타입/타입. 아마도 당신은 다른 디자인으로 가야 할 것입니다.

대부분의 현지화 프레임 워크/제공자/공장 (또는 무엇이든)은 모두 문자열 기반입니다. 이것 때문에, 다음과 같은 설계에 대한 생각이 당신이 인터페이스를 변경하지 않고, 기본 메시지 데이터 저장소에 키와 문화를 추가 할 수 있도록 할

public interface ILocalResources 
{ 
    string GetStringResource(string key); 
    string GetStringResource(string key, CultureInfo culture); 
} 

. 단점은 당연히 키를 변경해서는 안된다는 것입니다. 왜냐하면 그건 아마도 지옥 일 것이기 때문입니다.

또 다른 방법 추상 기본 유형이 될 수 :

public abstract class LocalResources 
{ 
    public string OkMessage { get { return this.GetString("OK"); } } 
    public string CancelMessage { get { return this.GetString("Cancel"); } } 
    ... 

    protected abstract string GetStringResource(string key, 
     CultureInfo culture); 

    private string GetString(string key) 
    { 
     Culture culture = CultureInfo.CurrentCulture; 

     string resource = GetStringResource(key, culture); 

     // When the resource is not found, fall back to the neutral culture. 
     while (resource == null && culture != CultureInfo.InvariantCulture) 
     { 
      culture = culture.Parent; 
      resource = this.GetStringResource(key, culture); 
     } 

     if (resource == null) throw new KeyNotFoundException(key); 

     return resource; 
    } 
} 

그리고 이러한 유형의 구현은 다음과 같이 수 : 키가 원하기 때문에,

public sealed class SqlLocalResources : LocalResources 
{ 
    protected override string GetStringResource(string key, 
     CultureInfo culture) 
    { 
     using (var db = new LocalResourcesContext()) 
     { 
      return (
       from resource in db.StringResources 
       where resource.Culture == culture.Name 
       where resource.Key == key 
       select resource.Value).FirstOrDefault(); 
     } 
    } 
} 

를이 방식은 두 세계의 최선을 다한다 ' 응용 프로그램을 통해 분산되어 새로운 속성을 추가하는 작업은 한 곳에서 수행해야합니다.

container.RegisterSingleton<LocalResources>(new SqlLocalResources()); 

그리고 LocalResources 유형이 모든 작업을 수행 정확히 하나의 추상 메소드를 가지고 있기 때문에,이 요청 방지하기 위해 캐싱을 추가하는 장식을 쉽게 만들 수 있습니다 : 당신의 favorite DI 라이브러리를 사용하면,이 같은 구현을 등록 할 수 있습니다 다음과 같이 당신은 장식을 적용 할 수 있습니다

public sealed class CachedLocalResources : LocalResources 
{ 
    private readonly Dictionary<CultureInfo, Dictionary<string, string>> cache = 
     new Dictionary<CultureInfo, Dictionary<string, string>>(); 
    private readonly LocalResources decoratee; 

    public CachedLocalResources(LocalResources decoratee) { this.decoratee = decoratee; } 

    protected override string GetStringResource(string key, CultureInfo culture) { 
     lock (this.cache) { 
      string res; 
      var cultureCache = this.GetCultureCache(culture); 
      if (!cultureCache.TryGetValue(key, out res)) { 
       cultureCache[key] = res= this.decoratee.GetStringResource(key, culture); 
      }     
      return res; 
     } 
    } 

    private Dictionary<string, string> GetCultureCache(CultureInfo culture) { 
     Dictionary<string, string> cultureCache; 
     if (!this.cache.TryGetValue(culture, out cultureCache)) { 
      this.cache[culture] = cultureCache = new Dictionary<string, string>(); 
     } 
     return cultureCache; 
    } 
} 

: 데이터베이스에서 동일한 데이터

container.RegisterSingleton<LocalResources>(
    new CachedLocalResources(new SqlLocalResources())); 

하지 마십시오 이 데코레이터는 문자열 리소스를 무기한 캐시하여 메모리 누수가 발생할 수 있으므로 문자열을 WeakReference 개의 인스턴스로 감싸거나 인스턴스에 만료 시간 제한을두고 싶습니다. 그러나 기존 구현을 변경하지 않고도 캐싱을 적용 할 수 있다는 아이디어가 있습니다.

이 정보가 도움이되기를 바랍니다.

+0

"ILocalResources"인터페이스의 확장 메서드를 구현할 수도 있지만, 단점은 속성 대신 메서드가 있다는 것입니다. 그러나 그렇게 나쁘지는 않을 것입니다. – Steven

관련 문제