본문 바로가기
프로그래밍/C#.net

추상화

by 건우아빠유리남편 2009. 8. 24.
반응형

추상메소드란 실체를 가지지않고, 메소드 의미만을 정의한 메소드입니다.
추상메소드의 실체는 base class에서 만들지 않고, 파생클래스에서 만듭니다.

또한, 추상클래스는 인스턴스를 생성할 수 없는 클래스로, 계승을 하는것을 전제로 한 클래스입니다.

 

■추상화

다용성에서 가상메소드의 이용예로써 Person클래스를 들었습니다.

이 Person base클래스에는 Age라는 프로퍼티가 있습니다만, 이 프로파티자체는 의미있는 값을 돌려주지않고,실체는 파생클래스의 Age프로퍼티에서 되었습니다.

 

class Person
{
  // 여기서 상관없는 이름은 생략.
  protected int age;

  public Person(int age){this.age  = age;}

  public virtual int Age
  {
    // base class에는 특히 의미없는 값을 돌려준다.
    // 의미있는 실체는 파생클래스에서 한다.
    get
    {
      return 0;
    }
  }
}
그러나,Person클래스처럼 의미없는 값을 돌려주는 메소드를 가지는 클래스의 인스턴스가 생성되어져버리는 것은 그다지 종은 일은 아닙니다.

 

이 문제를 해결하기위해서는 2가지 방법이 있습니다.

하나는 base class에 디폴트동작을 결정하는 방법입니다.

즉, 성선설을 믿고 Person이 디폴트로 정직한 답을 돌려줄것처럼 할것인지, 성악설을 믿고 Person이 디폴트로 나이를 속일것으로 할것인지,어쨌든,Person의 Age 프로퍼티가 어떤식의 의미를 가지는 값을 돌려주게끔 합니다.

class Person
{
  protected int age;

  public Person(int age){this.age  = age;}

  public virtual int Age
  {
    // 성선설을 믿어본다.
    // 보통사람은 모두 정직하게 나이를 말해준다.
    get
    {
      return this.age;
    }
  }
}

 

그리고 두번째는 Person클래스의 인스턴스를 생성되지 않게 하는 것입니다.

예를 들어, Person클래스의 콘스트럭터를 protect로 해버리면 Person클래스의 인스턴스는 외부에서 생성되지 않게 됩니다.

 class Person
{
  protected int age;

  // ↓ protected 이기때문에 외부에서 콘트스럭터를 부를수 없다.
  //    Person 은 계승해서 사용하는 전용 클래스가 된다.
  protected Person(int age){this.age  = age;}

  public virtual int Age{get{return 0;}}
}

 

이것으로 Person클래스의 인스턴스가 작성되어지는 것은 없어졌지만, 아직 Person클래스에 의미없는 메소드의 실구현이 남아있습니다. 이것은 의미없는 것으로 일부러 쓰지 않으면 안되는 삽질이 되어버리고, subclass에서 꼼꼼하게 오버로드하지 않으면 무의미한 값이 돌아오는 문제가 있습니다.

 

이 문제를 해결하기위해서, C#에는 인스턴스를 작성할수없는 클래스, 실구현이 없는(파생클래스에서 반드시 오버로드하지 않으면 안되는) 메소드를 정의하기위한 구문이 준비되어있습니다.

 

■추상클래스 

인스턴스를 작성할수없는 클래스를 추상클래스(abstract class)라도 부릅니다.

추상클래스를 작성하는것에는, 클래스를 정의 할때에 abstract 수식어를 붙입니다.

 

abstract class Person
{

  protected int age;

  // 추상클래스이기 때문에 콘스트럭터가 public 이라고 해도 인스턴스는 생성될수 없다.
  public Person(int age){this.age  = age;}

  public virtual int Age{get{return 0;}}

}

 

■추상메소드 

그리고, 실구현을 가지지않고, 의미만을 정의해서, 실구현은 파생클래스에서 행해지는 메소드를 추상메소드(abstract method)라고 부른다.

추상메소드를 작성하는것에는, 메소드를 정의할때에 abstract 를 붙입니다.

추상메소드는 추상클래스 안에서만 정의할수 있습니다.

 

abstract class Person
{
  protected int age;
  public Person(int age){this.age  = age;}
  public abstract int Age{get;} // 추상메소드에는 정의는 필요없다.
}

 

■예

using System;

abstract class Person
{
  protected string name;
  protected int age;

  public Person(string name, int age)
  {
    this.name = name;
    this.age  = age;
  }

  public string Name{get{return this.name;}}
  public abstract int Age{get;} // 추상메소드의 정의는 필요없다.
}

/// <summary>
/// 정직한 사람
/// 나이를 그대로 말한다.
/// </summary>
class Truepenny : Person
{
  public Truepenny(string name, int age) : base(name, age){}

  public override int Age
  {
    get
    {
      // 실제 나이를 그대로 돌려준다.
      return this.age;
    }
  }
}

/// <summary>
/// 거짓말쟁이
/// 나이를 속임.
/// </summary>
class Liar : Person
{
  public Liar(string name, int age) : base(name, age){}

  public override int Age
  {
    get
    {
      // 나이를 속임
      if(this.age < 20) return this.age;
      if(this.age < 25) return this.age - 1;
      if(this.age < 30) return this.age - 2;
      if(this.age < 35) return this.age - 3;
      if(this.age < 40) return this.age - 4;
      return this.age - 5;
    }
  }
}


class PolimorphismTest
{
  public static void Main()
  {
    Introduce(new Truepenny  ("춘향"  , 24)); //정직한 24살
    Introduce(new Liar       ("향단"   , 24));    //거짓말쟁이 24살
  }

  /// <summary>
  /// 자기소개를 한다.
  /// </summary>
  static void Introduce(Person p)
  {
    Console.Write("저는 {0} 입니다.\n", p.Name);
    Console.Write("저는 {0}살 입니다.\n\n", p.Age);
  }
}

 

참고

http://ufcpp.net/study/csharp/oo_abstract.html


반응형

'프로그래밍 > C#.net' 카테고리의 다른 글

[effective C#] item #3 : cast보다는 is나 as가 좋다.  (0) 2009.08.24
Interface  (0) 2009.08.24
virtual method  (0) 2009.08.24
계승  (0) 2009.08.24
정적변수,정적메소드  (0) 2009.08.24

댓글