OOP는 상속을 사용한다. 효율적이고 정돈되 코드를 위해 class의 공통 함수를 사용한다. 함수에 대해서 C#은 두가지 별도의 접근방식을 사용한다. virual 과 abstract methods이다. 둘다 polymorphism이 가능하지만, 구현과 사용방법은 상당히 다르다.
Virtual vs. Abstract
대중교통 사무실을 만들어보자. 사용자는 Car, Train, Plane 중에 선택할 수 있고 이동시간과 기본요금을 알 수 있다.
사용자의 옵션에 따라 대중교통 object를 초기화하는 CreateTransportMode() 함수를 갖는 TransportAgency class를 만들어보자.
public enum TransportModeType
{
Car,
Plane,
Train
}
internal class TransportAgency
{
public TransportMode CreateTransportMode(TransportModeType modeType)
{
return modeType switch
{
TransportModeType.Car => new Car(60),
TransportModeType.Train => new Train(4),
TransportModeType.Plane => new Plane(800),
_ => throw new ArgumentException("Invalid transport mode type."),
};
}
}
이제, GetTravelTime() abstract method와 CalculateBaseFare() virtual method를 정의하는 TransportMode abstract class를 만들자.
internal abstract class TransportMode
{
public abstract double GetTravelTime(double distance);
public virtual double CalculateBaseFare(double distance)
{
return distance * 0.5;
}
}
교통수단에 따라 이동시간을 계산하기 위해서 GetTravelTime() 함수를 사용한다. 교통수단에 따라 이동시간이 천차만별이므로 이 함수는 abstract 이다. 이 함수에서 기본 이동시간을 제공하지 않는다.
요금 계산을 하는 CalculateBaseFare()함수는 일반적으로 통용되는 기본요금을 제시하므로 virtual 함수로 만들어졌다. 자식 class는 총 요금 계산 시, 기본요금을 직접적으로 사용할지, 함수를 override해서 특정 요금 계산식을 구현할지 선택할 수 있다.
자식 class에서 abstract, virtual 함수가 어떻게 사용되는지 살펴보자.
자식 클래스
TransportMode abstract class를 상속받는 Car, Train, Plane 클래스를 작성해보자.
internal class Car(double averageSpeed) : TransportMode
{
private readonly double _averageSpeed = averageSpeed;
public override double GetTravelTime(double distance)
{
return distance / _averageSpeed;
}
public override double CalculateBaseFare(double distance)
{
return base.CalculateBaseFare(distance) + 2.5;
}
}
CalculateBaseFare를 override하여 계산식을 작성했다. base class로부터 기본 요금을 가져오고 연료값을 추가했다.
또한, GetTravelTime() abstract method도 override했다.
internal class Train(double fixedJourneyTime) : TransportMode
{
private double _fixedJourneyTime = fixedJourneyTime;
public override double GetTravelTime(double distance)
{
return _fixedJourneyTime;
}
public override double CalculateBaseFare(double distance)
{
var baseFare = base.CalculateBaseFare(distance);
if (distance > 500)
{
baseFare *= 0.9;
}
return baseFare;
}
}
긴 여행에서는 10% 할인을 제공하도록 CalculateBaseFare() 함수를 override했다.
internal class Plane(double cruisingSpeed) : TransportMode
{
private readonly double _cruisingSpeed = cruisingSpeed;
public override double GetTravelTime(double distance)
{
return distance / _cruisingSpeed + 0.5;
}
public override double CalculateBaseFare(double distance)
{
if (distance < 500)
{
return 100;
}
else if (distance < 1000)
{
return 150;
}
else
{
return distance * 0.2;
}
}
}
base class의 기본요금을 활용하지 않고, 완전히 새로운 계산식을 구현했다.
Virtual 와 Abstract Method의 차이점
Virtual Method | Abstract Method | |
Implementation | 기본 구현 있음 | 구현 없음 |
Overriding | 선택사항 | non-abstract class의 의무사항 |
Location | abstract, non-abstract class에 선언가능 | abstract class에만 선언가능 |
Purpose | 기본 기능을 override될 수 있도록 제공한다. | 자식 클래스에서 abstract methods를 반드시 구현하도록 한다. |
호환되지 않는 키워드 | static, abstract, private, override | static, virtual |
Flexibility | customization하기 좋다. | 일관성을 유지하기 좋다. |
결론
virtual, abstract method의 차이점을 살펴보았다. 해당 기능을 이해하면, C#에서 OOP를 구현하도록 도와준다. 다른 기능과, 신중하게 사용하므로 클림코드와 개선된 다형성과 확장성을 얻을 수 있다.
'C#' 카테고리의 다른 글
C#] SOLID 원칙 4. Interface Segregation Principle(인터페이스 분리 원칙) (1) | 2024.02.07 |
---|---|
C#] Access Modifiers (0) | 2024.02.02 |
C#] Value VS Reference Types (0) | 2024.02.01 |
C#] Class Variable, Class Reference, Class Instance의 차이점 (0) | 2024.01.31 |
C#] SOLID 원칙 3. Liskov Substitution Principle(리스코프 치환 원칙) (0) | 2024.01.26 |
댓글