2013-11-15 1 views
0

두 가지 문제점이 있습니다. 하나는 추상 싱글 톤 클래스를 갖기 위해 노력하고 있는데 싱글 톤 기능 + 약간의 추가 기능이 있지만이 클래스는 일반 (관련없는 싱글 톤)이기도합니다. 그것의 자식 클래스 중 하나가 코드를 다시 작성하지 않고 싱글 톤 기능을 상속 받기를 원하며 제네릭 형식에 의존하는 나머지 기능도 필요합니다.싱글 톤, 일반 및 상속 - 모든 자식 클래스가 싱글 톤 기능을 상속받습니다.

두 번째 문제는, 추상 클래스는 문자열 값을 받아야 기본값이 아닌 생성자를 가지고 있습니다. 이 문자열은 자식 클래스의 클래스 (추상 calss를 상속받은 클래스)에 의해 결정될 수 있습니다. 모든 파생 클래스의 따라서 비 추상적 인 인스턴스를 구현 할 수 있도록

  • 는 문자열 매개 변수를 반환하는 추상 클래스에 추상 정적 메서드를 추가합니다 다음과 같이

    내 생각은이 곳을 처리하는 수업은 잘될 것입니다. 정적 메서드는 추상이 될 수 없으므로 불가능합니다.

  • 문자열을 반환하는 정적 메서드로 인터페이스를 만들고 해당 제네릭 형식이 해당 인터페이스를 상속하는지 확인하십시오. 그런 다음 싱글 톤을 인스턴스화하면 T.GetTheString()을 호출하여 생성자에 매개 변수로 전달합니다. 인터페이스에는 정적 메서드가 없으므로 불가능합니다.

아이디어가 있으십니까? 여기

내 문제에 대해 설명 몇 가지 간단한 코드입니다 :

public abstract class NamedObject<T> { 
    private static NamedObject<T> _instance; 
    public static NamedObject<T> Instance { 
     get { 
      if (_instance == null) { 
       _instance = new NamedObject<T>("Need to determine this string from the non-abstract child class of NamedObject"); 
      } 
      return _instance; 
     } 
    } 

    private string objectName; 

    public NamedObject(string objectName) { 
     this.objectName = objectName; 
    } 

    public string GetFullName() { 
     return objectName + "(" + GetClassName() + ")"; 
    } 

    protected virtual string GetClassName() { 
     return typeof(T).ToString(); 
    } 
} 

주 내가 GetClassName()에 대한 일반 T를해야하고, 싱글 톤의 인스턴스를 생성하는 점에 유의, 나는의 정적 메서드를 호출해야 (불가능한 것 같다)이 클래스

편집을 상속 자식 클래스 : 더 나은 내 문제를 반영하기 위해 질문을 업데이트했습니다.


편집 : 도움을 주셔서 감사합니다. 두 번째 문제는 기본 생성자를 사용하고 자식 클래스의 비 정적 메서드 (기본 클래스의 추상)에서 생성자 내의 매개 변수로 간주되는 문자열을 가져 오는 것입니다.

는 또한, 싱글 상속의 내 전체 아이디어는 내가 롭 린든의 대답에 감사를 해결하기 위해 관리하는 잘못이었다. 그래서 때

public sealed class MyNamedObject : NamedObject<MyNamedObject, MyClass> 
{ 
    public MyNamedObject() : base() { 
    } 

    protected override string GetObjectName() { 
     return "MyName"; 
    } 
} 

:

public abstract class NamedObject<ME, T> where ME : NamedObject<ME, T>, new() 
{ 
    private static NamedObject<ME, T> _instance; 
    public static NamedObject<ME, T> Instance { 
     get { 
      if (_instance == null) { 
       _instance = new ME(); 
      } 
      return _instance; 
     } 
    } 

    private string objectName = "test"; 

    public NamedObject() { 
     this.objectName = GetObjectName(); 
    } 

    public string GetFullName() { 
     return objectName + "(" + GetClassName() + ")"; 
    } 

    protected virtual string GetClassName() { 
     return typeof(T).ToString(); 
    } 

    protected abstract string GetObjectName(); 
} 

그리고 자식 클래스 :

여기에 최종 코드 (나는 ... 이것은 단지 단순화 된 버전입니다, 그것은 이해가되지 않습니다 알고)입니다 처음으로 MyNamedObject.Instance을 호출하면 MyClass으로 NamedObject() 생성자가되고 T으로 objectName 매개 변수는 자식 클래스 MyNamedObject에 정의 된대로 "MyName"이됩니다.

정확히 내가 무엇을 찾고 있었습니까. 도움을 주신 모든 분들께 감사 드리며 매우 도움이되었습니다.

+0

여기서 무엇을하려고합니까? 추상 일반 싱글 톤? 새 NamedObject 을 만들 수 없습니다. 추상입니다. 추상적 싱글 톤은 무엇을 의미합니까? –

+0

오른쪽 ... 내가 잘못한 또 다른 일 :). 내 목표는 부모 클래스를 갖는 것이고 모든 자식 클래스는 자식 클래스 당 singletone 코드를 다시 작성하지 않고도 싱글 톤이 될 것입니다. – tbkn23

+0

필수 [싱글 톤은 나쁜 링크 임] (http://stackoverflow.com/questions/137975/what-is-so-bad-about-singletons). – Mike

답변

2

싱글 톤하지 마십시오. 이제까지.

어쨌든 여기에 가까운 사용 사례를 제시하는 방법 중 하나가 있습니다.

// base class 
public abstract class NamedObject<ME, T> where ME : NamedObject<ME, T>, new() 
{ 
    private static NamedObject<ME, T> _instance; 
    public static NamedObject<ME, T> Instance 
    { 
     get 
     { 
      if (_instance == null) 
      { 
       _instance = new ME { objectName = GetLabel(typeof(T)) }; 
      } 
      return _instance; 
     } 
    } 

    private string objectName; 

    public string GetFullName() 
    { 
     return objectName + "(" + GetClassName() + ")"; 
    } 

    protected abstract string GetLabel(Type type); 
    protected abstract string GetClassName(); 
} 
+0

이 방법이 효과가있을 수도 있습니다. – tbkn23

+0

좋아, 이건 나를 위해,하지만 몇 가지 작은 변경 사항 : 나는 원래의 T는 귀하의 스크립트에서 하위 클래스로 교체했다 필요했습니다. 대신, 나는 NamedObject 을 사용했다. 여기서 ME : NamedObject , new()'를 사용했다. T가 사용되는 유일한 장소는'typeof'에 있고, 나머지는 모두 ME입니다. 둘째, 나는'typeof' 값을 정말로 필요로하지 않았습니다. 유형에 의해 결정되는 문자열이 필요했지만 형식 자체는 필요하지 않았습니다. 결국 발견 한 해결책은 빈 생성자를 사용하는 것이었고 생성자 자체 내에서 추상 메소드를 호출했습니다. 최소한 첫 번째 부분의 답변을 업데이트하십시오. 동의 할 수 있습니다. – tbkn23

+0

완료. 그것이 당신을 위해 잘되기를 바랍니다. –

2

각 유형을 장식하는 속성을 소개하고 필요할 때 추출하는 것이 좋습니다. 컴파일 타임에 타입 이 올바른 타입 인을 가지고 있는지 확인할 수는 없지만 그렇게 할 수있는 방법은 많지 않습니다. 단위 테스트는, 그런 다음 싱글 톤 클래스 :

[AttributeUsage(AttributeTargets.Class)] 
public class NameAttribute : Attribute 
{ 
    public NameAttribute(string name) 
    { 
     this.Name = name; 
    } 

    public string Name { get; set; } 
} 

[Name("Foo")] 
public class SomeClass 
{ 
} 

위해 필요 스레드 안전하지 않은 특성을 갖는 대신 정적 생성자를 사용합니다 모든 종류.

private static readonly NamedObject<T> instance; 

static NamedObject() 
{ 
    // TODO: Validation :) 
    var attributes = typeof(T).GetCustomAttributes(typeof(NameAttribute), false); 
    var firstAttribute = ((NameAttribute[]) attributes)[0]; 
    string name = firstAttribute.Name; 
    instance = new NamedObject<T>(name); 
} 

public static NamedObject<T> Instance { get { return instance; } } 

Lazy<>을 대신 사용하십시오. 자세한 내용은 my article on singletons을 참조하십시오.

편집 : 명확히하기 위해 - 시작하려면 추상 클래스로 NamedObject을 사용해서는 안됩니다. 싱글 톤 및 상속 은 단순히을 함께 사용하지 마십시오. NamedObject<T>은 봉인 된 클래스 여야하며 T이라는 단일 인스턴스가 있습니다. T 인스턴스가 하나만 생성되도록 강요하지 않습니다.

+0

정적 생성자에 대해 알지 못했지만 정확하게 수행 할 필요가있는 것 같습니다 (장식이 없으면 이해가되지 않습니다 ... 대부분의 경우 C++ 사람이 더 많습니다.) 나는 그것을 밖으로 검사하고 당신에게 알릴 것이다. 감사. – tbkn23

+0

@ tbkn23 : 정적 생성자는 어디에서 이름을 가져올 지 문제를 해결하지 못합니다. * attributes *에 대한 아이디어를 적용 해 보겠습니다. 여기에서 읽어 보시기 바랍니다 : http://msdn.microsoft .com/en-us/library/z0w1kczw (v = vs.110) .aspx 정적 생성자는 스레드 안전을 정렬합니다. –

+0

흠 ... 실제로 정적 클래스 생성자는 자식 클래스가 상속받지 않기 때문에 도움이되지 않을 것이라고 생각합니다. 기본 단독 클래스를 만들고 모든 상속 클래스에 코드를 다시 작성하지 않고 자동으로 함수를 가져 오는 방법은 있습니까? ? 나는 당신의 링크를 읽을 것입니다, 고마워요. – tbkn23

0

이 당신이 원하는 일을해야한다 (우리는 싱글 톤 패턴거야 경우 Name 속성이 또한 추상적 인 방법이 될 수 속성으로 더 나은 것 같다).

class Program 
{ 
    static void Main(string[] args) 
    { 
     Console.WriteLine(MyNamedObject.Instance.Name); 
    } 
} 

public abstract class NamedObject<T> where T : NamedObject<T>, new() 
{ 
    private static T _instance; 

    public abstract string Name { get; } 

    public static T Instance 
    { 
     get { return _instance ?? (_instance = new T()); } 
    } 
} 

public class MyNamedObject : NamedObject<MyNamedObject> 
{ 
    public override string Name 
    { 
     get { return "My Named Object Name"; } 
    } 
}