인터페이스(Interface): 클래스나 구조체가 반드시 구현해야 하는 멤버의 목록을 정의하는 추상적인 타입. 메소드, 속성, 이벤트, 인덱스 등의 선언만 포함하며, 실제 구현은 인터페이스를 구현하는 클래스나 구조체에서 수행함. 인터페이스를 통해 클래스는 일관된 규칙을 따르도록 강제되며, 다형성을 지원해 코드의 확장성과 유연성을 높임.
특징
- 멤버 선언만 포함: 인터페이스에는 메소드, 속성, 이벤트, 인덱서의 선언만 포함되며, 구현은 포함되지 않음.
- 다중 상속 지원: 클래스의 다중 상속이 불가능하지만, 인터페이스는 여러 개를 동시에 구현할 수 있음.
- 계약(contract) 역할: 인터페이스는 특정 기능을 제공하겠다는 계약을 의미, 인터페이스를 구현한 클래스는 인터페이스의 모든 멤버를 구현해야 함.
- 다형성 지원: 인터페이스를 통해 다양한 클래스가 동일한 방식으로 사용될 수 있어, 코드의 유연성과 유지보수성이 높아짐.
//인터페이스 선언
public interface IMovable
{
void Move(int distance);
string Direction { get; set; }
}
//인터페이스 구현
public class Car : IMovable
{
public string Direction { get; set; }
public void Move(int distance)
{
Console.WriteLine($"자동차가 {Direction} 방향으로 {distance}km 이동했습니다.");
}
}
public class Bicycle : IMovable
{
public string Direction { get; set; }
public void Move(int distance)
{
Console.WriteLine($"자전거가 {Direction} 방향으로 {distance}km 이동했습니다.");
}
}
장점
- 유연한 설계: 인터페이스를 통해 서로 다른 클래스들이 동일한 규격을 따르도록 하여, 코드의 일관성과 유연성을 높임.
- 다중 상속 가능: 클래스 상속의 한계를 보완하여, 하나의 클래스가 여러 인터페이스를 구현할 수 있음.
- 다형성: 인터페이스를 통해 다형성을 구현할 수 있어, 동일한 방식으로 다양한 객체를 처리할 수 있음.
- 코드 유지보수성 향상: 인터페이스를 사용하면 코드의 구조를 명확해져 유지보수가 용이함.
인터페이스 상속: 다른 인터페이스를 상속할 수 있음. 인터페이스 간에 기능을 확장할 때 유용하며, 특정 인터페이스에 더 많은 기능을 추가할 수 있음. 클래스 상속과 달리, 다중 상속이 가능하며 한 인터페이스가 여러 인터페이스를 상속할 수 있음. 상속된 인터페이스는 상속받은 모든 인터페이스의 멤버를 포함하므로, 이를 구현하는 클래스는 상속받은 인터페이스의 모든 멤버를 구현해야 함.
public interface IMovable
{
void Move(int distance);
}
public interface IRotatable
{
void Rotate(int angle);
}
// IMovable과 IRotatable을 상속하여 기능을 확장한 인터페이스
public interface ITransformable : IMovable, IRotatable
{
void Scale(double factor);
}
//상속된 인터페이스 구현 예제
public class TransformableObject : ITransformable
{
public void Move(int distance)
{
Console.WriteLine($"객체가 {distance}만큼 이동했습니다.");
}
public void Rotate(int angle)
{
Console.WriteLine($"객체가 {angle}도 만큼 회전했습니다.");
}
public void Scale(double factor)
{
Console.WriteLine($"객체가 {factor}배로 확대/축소되었습니다.");
}
}
장점
- 기능의 계층적 확장: 인터페이스 상속을 통해 상위 인터페이스의 기본 기능을 확장하면서도, 구체적인 기능을 추가하여 더 세분화된 인터페이스를 만들 수 있음.
- 코드의 유연성과 재사용성: 인터페이스 상속을 사용하여 기능을 단계적으로 구현함으로써, 다른 클래스에서 상속받은 인터페이를 재사용하고 유연하게 확장할 수 있음.
- 다중 상속의 이점 활용: 인터페이스 간의 다중 상속이 가능하므로, 다양한 기능을 혼합하여 인터페이스를 구성할 수 있음.
//인터페이스 상속을 활용한 예제
public static void ApplyTransformation(ITransformable transformable)
{
transformable.Move(10);
transformable.Rotate(90);
transformable.Scale(1.5);
}
TransformableObject obj = new TransformableObject();
ApplyTransformation(obj);
// 출력:
// 객체가 10만큼 이동했습니다.
// 객체가 90도 만큼 회전했습니다.
// 객체가 1.5배로 확대/축소되었습니다.
추상 클래스(abstract Class): 구체적인 구현 없이 일부 기능만 정의하고, 이를 상속받는 클래스가 구체적인 기능을 구현하도록 요구하는 클래스. 직접 객체를 생성할 수 없으며 상속을 통해서만 사용할 수 있음. 추상 클래스는 일부 메소드는 구현하고, 일부는 자식 클래스에서 반드시 구현하도록 강제할 때 사용.
특징
- 인스턴스 생성 불가: 추상 클래스 자체로는 객체를 생성할 수 없음. 상속받은 자식 클래스에서만 인스턴스를 생성할 수 있음.
- 추상 메소드와 일반 메소드 포함: 추상 클래스는 추상 메소드(구현이 없는 메소드)와 일반 메소드(구현이 있는 메소드)를 모두 가질 수 있음.
- 상속을 통해 기능 강제: 추상 클래스에 선언된 추상 메소드는 자식 클래스에서 반드시 구현해야 함. 자식 클래스는 추상 메소드를 구첵적으로 정의해야 하며, 이를 통해 상속 구조에서 일관된 인터페이스를 제공할 수 있음.
- 공통 코드 재사용: 자식 클래스에서 공통으로 사용할 기능을 추상 클래스에 구현함으로써, 코드의 중복을 줄이고 재사용성을 높일 수 있음.
public abstract class Animal
{
// 추상 메서드: 구체적인 구현 없이 자식 클래스에서 구현을 강제
public abstract void Speak();
// 일반 메서드: 공통 기능을 구현할 수 있다.
public void Eat()
{
Console.WriteLine("동물이 음식을 먹습니다.");
}
}
//추상 클래스 상속 및 구현 예시
public class Dog : Animal
{
// 추상 메서드 구현
public override void Speak()
{
Console.WriteLine("강아지가 멍멍 짖습니다.");
}
}
public class Cat : Animal
{
// 추상 메서드 구현
public override void Speak()
{
Console.WriteLine("고양이가 야옹 울습니다.");
}
}
//사용예시
Animal dog = new Dog();
Animal cat = new Cat();
dog.Speak(); // 출력: 강아지가 멍멍 짖습니다.
dog.Eat(); // 출력: 동물이 음식을 먹습니다.
cat.Speak(); // 출력: 고양이가 야옹 울습니다.
cat.Eat(); // 출력: 동물이 음식을 먹습니다.
장점
- 공통 기능 제공: 공통 기능을 추상 클래스에서 정의하여 코드의 중복을 줄이고, 자식 클래스에서 공통 로직을 재사용할 수 있음.
- 구현 강제: 추상 메소드를 통해 자식 클래스에 특정 기능을 반드시 구현하도록 강제할 수 있음.
- 우연한 설계: 일부 기능은 구현하고, 일부는 추상 메소드로 남겨 자식 클래스에서만 구현하도록 할 수 있음.
추상 클래스와 인터페이스의 차이점
특성 | 추상 클래스 | 인터페이스 |
메소드 구현 | 일부 메소드를 구현할 수 있음. | 모든 멤버는 기본적으로 구현 없음. |
다중 상속 | 다중 상속 불가 | 다중 상속 가능 |
사용 목적 | 상속받는 클래스의 공통 기능 제공 | 계약(contract)역할로 일관된 인터페이스 제공 |
필드 포함 가능 | 필드 선언 가능 | 필드 선언 불가 |