디자인 패턴 - 싱글 설명

I. 서론

  싱글 톤 패턴은 비교적 간단 23 개 디자인 패턴해야한다, 그것은 관심의 객체를 생성, 디자인 패턴의 유형을 만들 속한다.

둘째, 개념

  싱글은 23 "명 중 4"디자인 패턴 중 하나 는 반복적 인 설계 문제를 해결하는 방법을 설명 가요 재사용 객체 지향 소프트웨어 개체 변경 테스트 및 재사용의 실현을 설계하기 위해서는 더 편리합니다.

싱글 톤 패턴은 다음과 같은 문제를 해결 :

  • 어떻게 클래스의 인스턴스가 하나만을 보장하기 위해?

  • 어떻게 쉽게 클래스의 고유 한 인스턴스에 액세스?
  • 어떻게 클래스의 인스턴스를 통제하기 위해?

  • 어떻게 클래스의 인스턴스의 수를 제한하려면?

싱글은 위의 문제를 해결하는 방법은?

  • 클래스 뒤에 생성자.
  • 클래스 반환 공공 정적 작업의 고유 한 인스턴스를 정의합니다.

이것의 핵심은 디자인 패턴 클래스는 자신의 인스턴스를 제어하는 ​​것입니다.

클래스 생성자 (정의 개인 생성자) 뒤에 클래스가 외부에서 인스턴스화 할 수없는 것을 확인합니다.

정적 기능을 사용하여 쉽게 클래스의 인스턴스에 액세스 (Singleton.getInstance ()).

셋째, 달성하기 위해

도 1에서, 예를 지연 단일

. (1)  은 USING 하여 System.Threading 단계;
 (2)  
. (3)      공용  클래스 SingletonTest을
 4.      {
 5.          개인  정적 SingletonTest 인스턴스 = 널을 ;
 . 6  
(7).          ///  <요약> 
8.          /// 숨겨진 클래스 생성자 (프라이빗 생성자)를 외부로부터 클래스 수 없도록 인스턴스화
 . 9          ///  </ 요약> 
10          개인 SingletonTest ()
 . 11          {
 12은              Console.WriteLine ( " ****** 단일 클래스가 인스턴스화 ****** " );
 13          }
 14  
15          // / <요약> 
16          /// 정적 클래스 인스턴스 쉽게 액세스 기능을 사용
 . 17          ///  </ 요약> 
18이다          ///  <반품> <= CREF 참조 "SingletonTest"/> </ 반환> 
. 19          공개  정적 하는 GetInstance () SingletonTest
 20은          {
 21 인              경우 (인스턴스 == )
 (22)가              {
 23 인                  경우 = 새로운 새 ; SingletonTest ()
 (24)              }
 (25)  
(26)는              , 예
 27          }
 28  
29          공중  공극 ) (PrintSomething
 30         {
 31              Console.WriteLine ($ "当前线程아이디为{Thread.CurrentThread.ManagedThreadId} " );
32              Console.WriteLine ( " 싱글 테스트 패턴 " );
33          }
 34      }

통상의 단일 스레드 동작의 경우, 상기 코드는, 하나의 실시 형태의 정의를 충족시킨다.

그러나 상황을 멀티 스레드?

우리는 테스트하려면 다음 코드를 사용하여

1  // 多线程情况
2               ( int로 I = 0 ; I는 < 10 ; ++ i가 )
 3              {
 4                  Task.Run (
 5                      () =>
 6                          {
 7                              SingletonTest singleton1 = SingletonTest.GetInstance ()
 8                              singleton1.PrintSomething () ,
 9                          });
10              }

결과는 다음과 같다

예상대로, SingletonTest 클래스는이 문제를 해결하는 방법을 다음 싱글의 요구 사항을 충족하지 않는, 여러 번 인스턴스화?

그것은 여러 스레드로 인한 문제가 있기 때문에, 스레드 동기화를 사용해야합니다. 우리는 잠금 장치의 사용을 구현하기 위해 여기에 있습니다.

. (1)      은 USING 시스템,
 (2)      은 USING 하여 System.Threading 단계;
 . 3  
. 4      공용  클래스 SingletonTest
 . 5      {
 . 6          개인  정적 SingletonTest 인스턴스 = ]
 . 7  
. 8          개인 정적 오브젝트 lockObject = 새로운 새로운 객체 ()
 . (9)  
(10)          ///  <요약> 
. 11          ///   감추기 클래스 (프라이빗 생성자)의 생성자는 클래스가 외부로부터 인스턴스화 할 수 있도록
 12          ///  </ 요약> 
13 인          전용 ) (SingletonTest을
 14          {
 15              에 Thread.sleep ( 500 );
16              Console.WriteLine ( " ****** 단일 클래스가 인스턴스화 ****** " )
 . (17)          }
 (18)이다  
.도 19          ///  <요약> 
20          /// 용이 정적 클래스의 인스턴스를 이용하여 액세스 기능
 (21)          / //  </ 요약> 
22 인          ///  <반품> <= CREF "SingletonTest"참조 /> </ 반환> 
(23)는          공용  정적 하는 GetInstance SingletonTest ()
 24          {
 25              // 재확인 잠금 단일 모드 실시 달성하는 수단 
(26) 인             경우 ( == null의 예)
 27              {
 28                 잠금 (lockObject)
 29                  {
 30                    경우 (예 == NULL)
 31                      {
 32                         인스턴스 = 새로운 SingletonTest ();
33                      }
 34                  }
 35              }
 36  
37             복귀 인스턴스;
38          }
 39  
40          공중  공극 PrintSomething ()
 41          {
 42              Console.WriteLine ($ " 当前线程이드为Thread.CurrentThread.ManagedThreadId {} " );
43              Console.WriteLine ( " 싱글 테스트 패턴 " );
44          }
45      }

코드는, 인스턴스를 생성하는 두 가지 예시가 비어 있는지 확인하기 전에, 그 필요가 있는지의 첫 번째 문장은 (상기 코드 라인 26)를 비우는? 이유는 무엇입니까? 우리는 클래스 인스턴스를 초기화 된 경우에 이러한 시나리오를 상상 내가 잠금을 획득해야합니까? 대답이 필요하므로하지 않은 제 1 판정 조건의 부가 (상기 코드 라인 26).

다음과 같은 결과가 다시 테스트 코드를 실행합니다 :

 결과에서, 클래스는 멀티 스레드 낮은 클래스를 여러 번 문제를 인스턴스화를 해결하기 위해, 한 번만 인스턴스화됩니다. 그러나이 명령은 영향력 재정렬 여부? 휘발성 키워드 여부? 에 오신 것을 환영합니다 추장은 대답합니다.

2, 하나의 예를 굶주리는 (권장)

조금 복잡 첫 번째 방법은, 당신은 단순히 그것을 가리킬 수 있습니다? 다음과 같이

 1     using System;
 2     using System.Threading;
 3 
 4     public class SingletonTest2
 5     {
 6         // 静态变量的方式实现单例模式
 7         private static readonly SingletonTest2 Instance = new SingletonTest2();
 8 
 9         private SingletonTest2()
10         {
11             Thread.Sleep(1000);
12             Console.WriteLine("******单例类被实例化******");
13         }
14 
15         public static SingletonTest2 GetInstance()
16         {
17             return Instance;
18         }
19 
20         public void PrintSomething()
21         {
22             Console.WriteLine($"当前线程Id为{Thread.CurrentThread.ManagedThreadId}");
23             Console.WriteLine("Singleton Pattern Test");
24         }
25     }

这种实现方式利用的是.NET中静态关键字static的特性,使单例类在使用前被实例化,并且只实例化一次,这个由.NET框架保证。

这种方式存在问题,在没有使用到类中的成员时候就创建实例了,能否在使用到类成员的时候才创建实例呢?如下图

 1 using System;
 2     using System.Threading;
 3 
 4     public class SingletonTest2
 5     {
 6         // 静态变量的方式实现单例模式
 7         private static readonly Lazy<SingletonTest2> Instance = new Lazy<SingletonTest2>(() => new SingletonTest2());
 8 
 9         private SingletonTest2()
10         {
11             Thread.Sleep(1000);
12             Console.WriteLine("******初始化单例模式实例*****");
13         }
14 
15         public static SingletonTest2 GetInstance()
16         {
17             return Instance.Value;
18         }
19 
20         public void PrintSomething()
21         {
22             Console.WriteLine($"当前线程Id为{Thread.CurrentThread.ManagedThreadId}");
23             Console.WriteLine("Singleton Pattern Test");
24         }
25     }

我们使用了Lazy关键字来延迟实例化。

四、例外

值得注意的是,反射会破坏单例模式,如下代码,能直接调用类的私有构造函数,再次实例化。

1 // 反射破坏单例
2 var singletonInstance = System.Activator.CreateInstance(typeof(SingletonTest2), true);

怎么避免呢?类的实例化都需要调用构造函数,那么我们在构造函数中加入判断标识即可。尝试实例化第二次的时候,就会抛异常。

 1         private static bool isInstantiated;
 2 
 3         private SingletonTest2()
 4         {
 5             if (isInstantiated)
 6             {
 7                 throw new Exception("已经被实例化了,不能再次实例化");
 8             }
 9 
10             isInstantiated = true;
11             Thread.Sleep(1000);
12             Console.WriteLine("******单例类被实例化******");
13         }

五、应用

那么实际应用中,哪些地方应该用单例模式呢?在这个类只应该存在一个对象的情况下使用。哪些地方用到了单例模式呢?

  • Windows任务管理器
  • HttpContext.Current

六、总结

俗话说,凡事都有两面性。单例模式确保了类只有一个实例,也引入了其他问题:

  • 单例模式中的唯一实例变量是使用static标记的,会常驻内存,不被GC回收,长期占用了内存
  • 在多线程的情况下,使用的都是同一个实例,所以需要保证类中的成员都是线程安全,不然可能会导致数据混乱的情况

代码下载:https://github.com/hzhhhbb/SingletonPattern

七、参考资料

 

추천

출처www.cnblogs.com/hzhhhbb/p/11373553.html