2022. 1. 14. 00:00ㆍCSharp/Basic
상속,다형성,추상화
상속
상위 클래스의 동작을 재사용(상속), 확장 또는 수정하는 하위 클래스를 정의하는 행위
멤버가 상속되는 클래스를 기본 클래스 라고 한다.
기본 클래스의 멤버를 상속하는 클래스를 파생 클래스 라고 한다.
public class BaseClass
{
/// <summary>
/// virtual keyword 를 통해 BaseClass를 상속한 ChildClass 에서
/// Exectue() 메소드를 재정의 (overriding) 가능하도록 만든다.
/// </summary>
/// <returns></returns>
public virtual void Execute()
{
Console.WriteLine($"{nameof(BaseClass)} Execute");
}
}
public class ChildClass : BaseClass
{
/// <summary>
/// override keyword 를 통해 BaseClass 를 상속한 ChildClass 에서
/// Execute 메소드를 재정의 합니다.
/// </summary>
public override void Execute()
{
Console.WriteLine($"{nameof(ChildClass)} Execute");
}
}
public class BaseClass
{
private int _id; // BaseClass 내부 에서만 접근, 상속 클래스 에서 접근 안됨
protected int _age; // BaseClass 내부 에서 접근, 상속 클래스 에서 접근
protected string MyName { get; set; } // BaseClass 내부 에서 접근, 상속 클래스 에서 접근
internal string Description { get; set; }// 같은 assembly 내에서 접근가능. BaseClass 내부, 외부, 상속 클래스 에서 접근
public string Title { get; set; }// 모든 assembly 에서 접근 가능. BaseClass 내부, 외부, 상속 클래스 에서 접근
......
......
}
다형성
프로그램 언어 각 요소들(상수, 변수, 식, 객체, 메소드 등)이 다양한 자료형(type)에 속하는 것이 허가되는 성질.
하나의 타입에 여러 객체를 대입할 수 있는 성질
public class Polymorphism
{
public class Shape
{
// 몇몇 member 들
public int X { get; private set; }
public int Y { get; private set; }
public int Height { get; set; }
public int Width { get; set; }
// virtual keyword 를 통해 재정의가 가능하게 만든 method
public virtual void Draw()
{
Console.WriteLine("Performing base class drawing tasks");
}
}
public class Circle : Shape
{
public override void Draw()
{
// Code to draw a circle...
Console.WriteLine("Drawing a circle");
base.Draw();
}
}
public class Rectangle : Shape
{
public override void Draw()
{
// Code to draw a rectangle...
Console.WriteLine("Drawing a rectangle");
base.Draw();
}
}
public class Triangle : Shape
{
public override void Draw()
{
// Code to draw a triangle...
Console.WriteLine("Drawing a triangle");
base.Draw();
}
}
}
var shapes = new List<Polymorphism.Shape>
{
new Polymorphism.Rectangle(),
new Polymorphism.Triangle(),
new Polymorphism.Circle()
};
foreach (var shape in shapes)
{
shape.Draw();
}
/* Output:
Drawing a rectangle
Performing base class drawing tasks
Drawing a triangle
Performing base class drawing tasks
Drawing a circle
Performing base class drawing tasks
*/
우리는 위에서 Shape 라는 base class 에 Retangle, Triangle, Circle 의 instance 를 저장했다.
그리고 그것들을 저장한 List<Shape> shapes 라는 각 변수를 foreach 를 통해 실행 하고 있다.
만약 우리가 Shape 라는 BaseClass 로 부터 상속받지 않았다면
각각의 Rectangle, Triangle, Circle 을 foreach 를 통해 처리 하기 정말 힘들어졌을 것이다.
다형성은 이렇게 하나의 type (base class) 의 method (Draw) 가
다양한 type 들을 처리할 수 있게 해준다.
위에서 Shape.Draw() 를 Triangle 에서 호출 하려면 어떻게 해야 할까?
base.Draw() 를 호출 하면 된다. 위 코드에서 이미 구현 되어 있다.
이러한 다형성을 이용해서 우리는 좀더 많은 유연성을 객체에 줄수 있다.
객체지향 프로그램의 꽃이라고 할 수 있을 만한 기능이다.
추상화
복잡한 자료, 모듈, 시스템 등으로부터 핵심적인 개념 또는 기능을 간추려 내는 것
public class Abastract
{
public class Shape
{
// virtual keyword 를 통해 재정의가 가능하게 만든 method
public virtual void Draw()
{
Console.WriteLine($"Performing base class drawing tasks, {GetClassName()}");
}
public virtual string GetClassName()
{
return nameof(Shape);
}
}
public class Circle : Shape
{
public override void Draw()
{
Console.WriteLine($"Drawing a {GetClassName()}");
base.Draw();
}
public override string GetClassName()
{
return nameof(Circle);
}
}
public class Rectangle : Shape
{
public override void Draw()
{
// Code to draw a rectangle...
Console.WriteLine($"Drawing a {GetClassName()}");
base.Draw();
}
public override string GetClassName()
{
return nameof(Rectangle);
}
}
public class Triangle : Shape
{
public override void Draw()
{
// Code to draw a triangle...
Console.WriteLine($"Drawing a {GetClassName()}");
base.Draw();
}
public override string GetClassName()
{
return nameof(Triangle);
}
}
}
위의 클래스는 다형성에 있는 class 를 조금 수정 하였다.
GetClassName 이라는 것을 만들었고 GetClassName 은 class 의 이름을 return 한다.
이제 위 class 를 refactoring 해볼 것이다.
Draw 를 확인해 보면 모두 같은 걸 알수 있다. 과연 이것을 어떻게 처리 해야 할까?
여기서 핵심은 Draw 가 모든 코드에 있을 필요가 없다는 것이다.
어떤 부분을 추상화 하고 어떤부분을 상속해야 할까?
이제 이부분에 집중해서 code 로 구현해 보자
public class Abastract
{
public class Shape
{
// virtual keyword 를 통해 재정의가 가능하게 만든 method
public virtual void Draw()
{
PrintDraw();
Console.WriteLine($"Performing base class drawing tasks, {GetClassName()}");
}
public virtual string GetClassName()
{
return nameof(Shape);
}
protected virtual void PrintDraw()
{
Console.WriteLine($"Drawing a {GetClassName()}");
}
}
public class Circle : Shape
{
public override string GetClassName()
{
return nameof(Circle);
}
}
public class Rectangle : Shape
{
public override string GetClassName()
{
return nameof(Rectangle);
}
}
public class Triangle : Shape
{
public override string GetClassName()
{
return nameof(Triangle);
}
}
}
각 상속 class 들에서 Draw 를 삭제했다.
PrintDraw() 라는 method 를 virtual 로 만들었고
만약 하위 class 에서 이부분을 수정해야 한다면 확장 가능하도록 만들었다.
이 PrintDraw 에 Draw 의 base.Draw 를 제외한 내용이 있다.
그리고 shape 에서 Draw 를 재 구현 하여 PrintDraw() 를 호출 하도록 수정 하였다.
여기서 우리는 Draw 를 추상화 하였고 확장을 위해 PrintDraw 를 만들어 냈다. 이또한 추상화의 한 과정이다.
C# 에서는 abstract 라는 keyword 를 통해 class 에 명시적으로 추상 클래스 또는 method 라는 내용을 지정할 수 있다.
다음을 확인 하자. 약간의 refactoring 을 거치면 다음과 같이 된다.
public class Abastract
{
public abstract class AbstractShape
{
abstract public void Draw();
abstract protected void PrintDraw();
}
public class Shape: AbstractShape
{
public override void Draw()
{
PrintDraw();
Console.WriteLine($"Performing base class drawing tasks, {GetClassName()}");
}
protected virtual string GetClassName()
{
return GetType().Name;
}
protected override void PrintDraw()
{
Console.WriteLine($"Drawing a {GetClassName()}");
}
}
public class Circle : Shape{}
public class Rectangle : Shape{}
public class Triangle : Shape{}
}
abstract keyward 가 있는 class 는 그것 자체로 instance 화 될수 없고 항상 abstract class 를 상속한 class 가 필요하다.
이와 같이 C# 에서는 abstract 를 통해 추상화를 명시적으로 표현하고 있다.
관련영상
'CSharp > Basic' 카테고리의 다른 글
C# Basic Tutorial (Class - 멤버사용법 및 기타등등) (0) | 2022.01.13 |
---|---|
C# Basic Tutorial (Class - 생성자) (0) | 2022.01.12 |
C# Basic Tutorial (Method 2/2) (0) | 2022.01.11 |
C# Basic Tutorial (Method 1/2) (0) | 2022.01.10 |
C# Basic Tutorial (Arrays) (0) | 2022.01.09 |