static class vs singleton design pattern

공용 데이터를 저장하여 사용하고자 할 때, singleton 패턴이나 static 클래스를 사용한다.

싱글톤 패턴 (Singleton design pattern)
-싱글톤 패턴이란 single instance object(해당 클래스의 인스턴스 하나)가 만들어지고, 어디서든지 그 싱글톤에 접근할 수 있도록 하기 위한 패턴

정적 클래스 (Static class)
-static 키워드를 사용한 정적 클래스는 정적 멤버만 포함 가능
-정적 클래스는 new 키워드를 사용하여 정적 클래스의 인스턴스를 생성할 수 없음
-정적 클래스는 봉인 클래스 (sealed class) 임
-static 클래스는 single-instance, global 데이터를 저장하여 사용하는 용도로 적당
-그러나, 싱글톤은 인자(parameter)나 객체(object)로 사용가능하나 정적클래스는 불가능

http://dis.dankook.ac.kr/lectures/hci10/entry/singleton-pattern과-static-class-비교

Instance vs Static Constructor

C#은 두 가지 종류의 constructor, 즉 class constructor(static constructor), instance constructor(non-static constructor)를 지원한다.
http://dis.dankook.ac.kr/lectures/hci10/entry/static-constructor와-instance-constructor-비교

Static Constructor

-static constructor는 static data member를 초기화하는데 사용
-static constructor는 접근 지정자를 쓸수 없음
-static constructor는 인자를 가질 수 없음
-static constructor는 non-static data member를 접근할 수 없음


-static constructor는 non-static data member를 접근할 수 없음


// Test.cs
class Test
{
//Declaration and initialization of static data member
private static int id = 5;
public static int Id
{
get
{
return id;
}
}

public static void print()
{
Console.WriteLine(“Test.id=” + id);
}
}

class Program
{
static void Main(string[] args)
{
Test.print(); // 정적 메소드를 사용하여 Test.id를 출력
}
}

Test.id=5



// Test1.cs
class
Test1
{
private static int id;

// static constructor를 사용하여 Test.id값에 따라서 Test1.id를 지정
static
Test()
{
if
( Test.Id < 10 )
{
id = 20;
}
else
{
id = 100;
}
}

public static void print()
{
Console.WriteLine(“Test.id=” + id);
}
}

class Program
{
static void Main(string[] args)
{
Test1.print(); // 정적 메소드를 사용하여 Test.id를 출력
}
}

Test.id=20 // 정적 생성자 내에서 Test.id=5였기때문에 Test.id=20

Instance Constructor
-instance constructor는 new 키워드를 사용하여 객체 생성에 사용
-instance constructor는 일반적으로 constructor라고 불림
constructor initializer는 생성자들 코드를 간략하게 만들기 위해 사용


public class MySimpleClass
{
public MySimpleClass (int x)
{
Console.WriteLine (x);
}
}


 


// 위의 코드는 컴파일러에서 아래의 코드처럼 해석
public
class MySimpleClass
{
public MySimpleClass (int x) : base()
{
Console.WriteLine (x);
}
}


 


public class MyClass
{
private ArrayList col;
private string name;
public MyClass() : this(0,””) // 생성자 초기화목록을 사용하여 기본 생성자 지정
{
}
public MyClass(int initialCount) : this (initialCount, “”)
{
}
public MyClass(int initialCount, string name)
{
col = (initialCount > 0) ? new ArrayList(initialCount) : new ArrayList();
this.name = name;
}
}


-default constructor가 지정되어 있지 않다면 컴파일러에서 자동 생성해줌


public class MySimpleClass
{
int someMemberVariable;
}
// 위의 코드를 컴파일러에서 아래와 같이 해석함
public class MySimpleClass
{
int someMemberVariable;

public MySimpleClass() : base()
{
}
}

-constructor는 상속되지 않음
public class MyBaseClass
{
public MyBaseClass (int x)
{
}
}

public class MyDerivedClass : MyBaseClass
{
// This constructor itself is okay – it invokes an
// appropriate base class constructor
public MyDerivedClass () : base (5)
{
}

public static void Main()
{
new MyDerivedClass (10); // ERROR: MyDerivedClass는 인자를 받는 생성자가 없음
}
}

 

Instance vs Static Method

Static Method (일면 Class Method)
-메서드 선언에 static 한정자가 있는 경우 해당 메서드를 정적 메서드라고 한다.
-정적 메서드는 class method나 static member field 조작을 위한 메소드이다.
-정적 메서드 내에서 클래스의 instance field나 method는 접근 불가능하다.
-정적 메서드는 특정 인스턴스에서는 작동되지 않으므로, 정적 메서드 내에서 this를 참조하면 컴파일 타임 오류가 발생한다.

Instance Method
-인스턴스 메서드는 클래스의 지정된 인스턴스에서 작동한다.
-인스턴스 메서드 내에서는 this로 액세스할 수 있다.

class ValueClass
{
    private int value = 0;
    public void setValue(int value) { this.value = value; }
    public int getValue() { return this.value; }
    public void print() { Console.WriteLine(“value={0}”, this.value);
    public static void printString(string str) { Console.WriteLine(str); }
}
class Program
{
    static void main(string[] args)
    {
        ValueClass c = new ValueClass();
        c.setValue(10); // 인스턴스 메소드
        c.print(); // 인스턴스 메소드
        ValueClass.printString(“test”); // 정적 메소드 (클래스명.정적메소드명)
    }
}

Instance vs Static Field

Static Field (일명 Class Field)
-전역 데이터, 공유 데이터로 클래스 로딩 시 공간을 할당
-한 클래스에 하나만 정적 필드가 할당됨
-클래스명.정적필드명으로 사용
-클래스 객체의 개수를 카운트하거나 유틸리티 값들을 저장하는 경우 사용함

Instance Field
-객체의 현재 상태를 저장할 수 있는 자료
-객체가 생성될 시 메모리 공간을 할당
-객체명.객체필드명으로 사용


class ValueClass
{
    private int value = 0; // 인스턴스 필드
    public static int count = 0; // 정적 필드
    public ValueClass() { count++; }
    public void setValue(int value) { this.value = value; } // 인스턴스 메소드
    public int getValue() { return this.value; } // 인스턴스 메소드
    public void print() { Console.WriteLine(“value={0}”, this.value); } // 인스턴스 메소드
    public static void printString(string str) { Console.WriteLine(str); } // 정적 메소드
    public static int getCount() { return count; } // 정적 메소드
}

class Program
{
    static void main(string[] args)
    {
        ValueClass c1 = new ValueClass();
        c1.setValue(10); // 인스턴스 메소드
        c1.print(); // 인스턴스 메소드 value=10
        ValueClass.printString(“test”); // 정적 메소드 (클래스명.정적메소드명) test
        ValueClass c2 = new ValueClass();
        c2.setValue(20); // 인스턴스 메소드
        c2.print(); // 인스턴스 메소드 value=20
        Console.WriteLine(“number of ValueClass: {0}”, ValueClass.getCount()); // 정적 메소드 (클래스명.정적메소드명) number of ValueClass: 2
       
Console.WriteLine(“number of ValueClass: {0}”, ++ValueClass.count); // 정적 필드 (클래스명.정적필드명) number of ValueClass: 3
    }
}

const vs readonly Field

const 상수(constant)은 컴파일타임(compile-time) 상수이다.
readonly 상수(constant)은 런타임(run-time) 상수이다.



// const
public const int Millennium = 2000;
public const double PI = 3.141592;

// readonly
public static readonly int ThisYear = 2010;
public class MyClass
{
    public readonly double PI;
    public MyClass()
    {
        PI = 3.141592;
    }
}

const 상수는 선언하는 순간부터 static 된다.
const 상수를 선언함과 동시에 초기화를 해주어야 한다.
const 상수는 컴파일시 값이 결정 되어져 있어야 한다.

readonly 상수는 static 키워드를 사용하면 static 상수가 된다. 사용하지 않으면 일반상수가 된다.
readonly 상수는 const 키워드를 사용하는 것처럼 반드시 초기화 필요없.
readonly 상수는 생성자를 통해서 런타임시 값이 결정될 있다.
한번 값이 결정되면 다시는 값을 변경할 수는 없다.

class

protected 접근자
-protected 접근 지정자를 사용한 멤버 필드와 메소드는 파생 클래스에서는 사용가능하나 클래스 외부에서는 호출하지 못함


static 필드와 메소드
-static field는 전역 데이터로 클래스당 하나만 할당됨
-클래스명.정적필드명 형태로 사용
-static method는 class method나 static member field 조작을 위한 메소드
-static method는 instance field는 접근 불가능

constructor (생성자)
-default constructor (기본 생성자)
-constructor overloading (생성자 오버로딩) 생성자를 여러 가지 형태로 정의
-constructor initializer (생성자 초기화 목록) 생성자들 사이의 정의가 비슷한 경우 코드를 간략하게 만들기 위해 사용

-private constructor (private 생성자) 정적 멤버만 포함하는 클래스에서 사용하며 클래스가 인스턴스화 될 수 없음을 분명히 하기 위해 private 접근 지정자를 사용
-static constructor (static 생성자) 정적 데이터 멤버를 초기화하는데 사용

destructor (소멸자)
-객체가 소멸될 때 필요한 정리 작업을 정의하는 부분    

0부터 100까지 숫자만 입력받기


int value;  // needed for TryParse
string str; // needed for ReadLine


Console.Write(“0부터 100까지 숫자를 입력하세요: “);
str = Console.ReadLine();
while ((!int.TryParse(str, out value)) || (value < 0 || value > 100))
{
        Console.Write(“다시 0부터 100까지 숫자를 입력하세요: “);
        str = Console.ReadLine();
}
int result = int.Parse(str);
Console.WriteLine(“입력된 숫자=” + result);

ESCAPE 키가 눌린게 아니면 프로그램이 계속 실행되기

    class Program
    {
        static double Add(double a, double b)
        {
            return (a + b);
        }


        static void Main(string[] args)
        {
            do
            {
                Console.Write(“a를 입력하세요: “);
                string str = Console.ReadLine();
                double a;
                bool result = double.TryParse(str, out a);


                Console.Write(“b를 입력하세요: “);
                str = Console.ReadLine();
                double b;
                result = double.TryParse(str, out b);


                double c = Add(a, b);
                Console.WriteLine(“결과는 {0}”, c);


                Console.WriteLine(“다시 하려면 ENTER 키를 누르시고 종료하려면 ESC 키를 누르세요”);
            } while (Console.ReadKey().Key != ConsoleKey.Escape);
        }
    }