목차
본 포스팅은 C#에서 인터페이스와 추상 클래스를 사용하는 방법을 다룬다. 우선 인터페이스와 추상 클래스는 상세한 설명 없이 예시로만 간단히 작성하였고, 자세한 사항을 두 개념의 비교 부분에서 자세히 다룬다. 이를 통해 각각의 기능을 정확히 이해하고 언제 사용하면 적합할지 학습할 수 있다.
1. 인터페이스 사용법
C#에서 인터페이스는 객체 지향 프로그래밍의 핵심 요소 중 하나이다. 인터페이스를 통해 다양한 클래스가 동일한 계약을 따르도록 하여, 코드의 유연성과 재사용성을 높일 수 있다. 아래 예시에서는 C# 인터페이스의 기본적인 사용법부터, 다중 인터페이스 구현, 명시적 인터페이스 구현, 그리고 인터페이스 상속에 이르기까지의 예시를 소개한다.
1.1 기본 예시
// 기본 예시
using System;
// 인터페이스 정의
interface IAnimal
{
void MakeSound(); // 소리내는 행위를 정의하는 메서드
}
// Dog 클래스는 IAnimal 인터페이스를 구현
class Dog : IAnimal
{
public void MakeSound()
{
Console.WriteLine("멍멍!");
}
}
// Cat 클래스는 IAnimal 인터페이스를 구현
class Cat : IAnimal
{
public void MakeSound()
{
Console.WriteLine("야옹!");
}
}
// 메인 프로그램
class Program
{
static void Main()
{
IAnimal dog = new Dog();
IAnimal cat = new Cat();
dog.MakeSound(); // "멍멍!" 출력
cat.MakeSound(); // "야옹!" 출력
}
}
1.2. 다중 인터페이스 구현
여러 인터페이스를 하나의 클래스에서 구현할 수 있다.
// 다중 인터페이스 구현
using System;
// 동물과 비행이 가능한 객체를 위한 인터페이스 정의
interface IAnimal { void MakeSound(); }
interface IFlyable { void Fly(); }
// Bird 클래스는 IAnimal과 IFlyable 인터페이스를 모두 구현
class Bird : IAnimal, IFlyable
{
public void MakeSound()
{
Console.WriteLine("새가 지저귑니다.");
}
public void Fly()
{
Console.WriteLine("새가 날아갑니다.");
}
}
// 메인 프로그램
class Program
{
static void Main()
{
Bird bird = new Bird();
bird.MakeSound(); // "새가 지저귑니다." 출력
bird.Fly(); // "새가 날아갑니다." 출력
}
}
1.3. 명시적 인터페이스 구현
두 인터페이스에서 동일한 이름의 메서드를 가질 때 명시적 인터페이스 구현으로 충돌을 해결할 수 있다.
using System;
interface IDog {void Bark();}
interface ICat {void Bark();}
class Animal : IDog, ICat
{
void IDog.Bark() {Console.WriteLine("강아지가 짖습니다.");}
void ICat.Bark() {Console.WriteLine("고양이가 울부짖습니다.");}
}
class Program
{
static void Main()
{
Animal animal = new Animal();
((IDog)animal).Bark();
((ICat)animal).Bark();
}
}
1.4. 인터페이스 상속
인터페이스가 다른 인터페이스를 상속할 수 있다.
using System;
interface IAnimal {void MakeSound();}
interface IFlyableAnimal : IAnimal {void Fly();}
class Bird : IFlyableAnimal
{
public void MakeSound() {Console.WriteLine("새가 지저귑니다.");}
public void Fly() {Console.WriteLine("새가 날아갑니다.");}
}
class Program
{
static void Main()
{
Bird bird = new Bird();
bird.MakeSound(); // "새가 지저귑니다." 출력
bird.Fly(); // "새가 날아갑니다." 출력
}
}
2. 추상 클래스 사용법
추상 클래스는 C#에서 객체 지향 프로그래밍의 중요한 요소 중 하나로, 특정 클래스가 완전히 구현되지 않아 인스턴스화될 수 없는 클래스를 의미한다. 이 섹션에서는 추상 클래스의 기본 사용법부터, 상속 및 메서드 오버라이딩, 그리고 추상 클래스 내의 필드와 생성자 사용까지를 다룬다.
2.1 기본 예시
using System;
// 추상 클래스 정의
public abstract class Animal
{
// 추상 메서드 정의
public abstract void MakeSound();
// 일반 메서드도 포함 가능
public void Sleep()
{
Console.WriteLine("잠을 잔다.");
}
}
// Dog 클래스는 Animal 추상 클래스를 상속받음
public class Dog : Animal
{
// 추상 메서드 구현
public override void MakeSound()
{
Console.WriteLine("멍멍!");
}
}
// 메인 프로그램
class Program
{
static void Main()
{
Dog dog = new Dog();
dog.MakeSound(); // "멍멍!" 출력
dog.Sleep(); // "잠을 잔다." 출력
}
}
2.2 상속과 메서드 오버라이딩
추상 클래스를 상속받는 클래스는 추상 클래스에서 정의된 모든 추상 메서드를 구현해야 한다. 이를 통해 코드의 재사용성과 확장성을 보장한다.
using System;
// 추상 클래스 정의
public abstract class Bird
{
public abstract void Fly();
// 추상 클래스에서 일반 메서드 정의
public void Eat()
{
Console.WriteLine("먹는다.");
}
}
// Eagle 클래스는 Bird 추상 클래스를 상속받아 메서드를 구현
public class Eagle : Bird
{
public override void Fly()
{
Console.WriteLine("독수리가 하늘을 난다.");
}
}
class Program
{
static void Main()
{
Eagle eagle = new Eagle();
eagle.Fly(); // "독수리가 하늘을 난다." 출력
eagle.Eat(); // "먹는다." 출력
}
}
2.3 필드와 생성자 사용
추상 클래스는 상태를 저장할 수 있는 필드와 생성자를 포함할 수 있으며, 이는 상속받는 클래스에서 활용될 수 있다.
using System;
// 추상 클래스 정의
public abstract class Vehicle
{
protected int wheels;
// 생성자를 통해 필드 초기화
public Vehicle(int numberOfWheels)
{
wheels = numberOfWheels;
}
// 추상 메서드
public abstract void Start();
// 일반 메서드
public void Stop()
{
Console.WriteLine("차량이 멈춘다.");
}
}
// Car 클래스는 Vehicle 추상 클래스를 상속받음
public class Car : Vehicle
{
public Car() : base(4) // 차량의 바퀴 수는 4로 초기화
{
}
public override void Start()
{
Console.WriteLine($"차량이 {wheels} 바퀴로 움직인다.");
}
}
class Program
{
static void Main()
{
Car car = new Car();
car.Start(); // "차량이 4 바퀴로 움직인다." 출력
car.Stop(); // "차량이 멈춘다." 출력
}
}
이 세션에서는 추상 클래스의 다양한 활용 방법을 소개하였다. 추상 클래스를 사용하면 코드의 일관성과 재사용성을 향상시킬 수 있으며, 객체 지향 설계의 유연성을 증가시킬 수 있다.
3. 인터페이스 vs 추상 클래스 비교
인터페이스와 추상 클래스는 유사해 보이지만 기본적인 차이가 있다. 인터페이스는 모든 메서드가 기본적으로 추상 메서드로 정의되며, 어떠한 필드도 포함할 수 없다. 반면, 추상 클래스는 추상 메서드와 일반 메서드를 모두 포함할 수 있으며, 필드도 가질 수 있다. 인터페이스는 다중 상속이 가능하지만, 추상 클래스는 단일 상속만 가능하다. 이는 인터페이스가 설계 단계에서 타입의 행동을 정의하는 데에 초점을 맞춘 반면, 추상 클래스는 일부 기능이 구현된 상태로 상속받을 수 있도록 함으로써 좀 더 구체적인 구현을 제공하기 때문이다.
3.1 주요 차이점 설명
- 인터페이스
- 메서드: 메서드 명칭만 명시 (추상 메서드)
- 필드: 필드를 정의할 수 없음 (상태를 저장할 수 없음)
- 상속: 다중 상속 가능.
- 목적: 타입의 행동을 정의
- 추상 클래스
- 메서드: 메서드 구현도 가능 (추상 메서드 + 일반 메서드)
- 필드: 필드를 포함할 수 있어 상태 정보를 저장함.
- 상속: 단일 상속만 가능.
- 목적 : 타입의 행동과 일부 구현을 제공
3.2 비교 예제
인터페이스 예제: 다음 예시는 인터페이스를 통한 다중 상속을 구현하고 각 클래스가 인터페이스의 메서드를 어떻게 구현하는지 보여준다.
using System;
// 두 개의 인터페이스 정의
public interface IEngine
{
void StartEngine(); // 엔진 시작 메서드
}
public interface ILights
{
void ToggleLights(); // 조명 토글 메서드
}
// Car 클래스는 IEngine과 ILights 인터페이스를 모두 구현
public class Car : IEngine, ILights
{
public void StartEngine()
{
Console.WriteLine("Car engine started.");
}
public void ToggleLights()
{
Console.WriteLine("Car lights toggled.");
}
}
class Program
{
static void Main()
{
Car myCar = new Car();
myCar.StartEngine(); // "Car engine started."
myCar.ToggleLights(); // "Car lights toggled."
}
}
추상 클래스 예제: 추상 클래스에서는 필드를 포함할 수 있고, 일부 메서드에 대한 구현을 제공한다.
using System;
// 추상 클래스 정의
public abstract class Vehicle
{
protected int wheelCount; // 차량의 바퀴 수를 나타내는 필드
public Vehicle(int wheels)
{
wheelCount = wheels;
}
public abstract void Start(); // 추상 메서드는 파생 클래스에서 구현해야 함
public void Stop() // 상세 구현이 가능
{
Console.WriteLine("Vehicle stopped."); // 모든 차량이 공통적으로 사용할 정지 메서드
}
}
// 추상 클래스 상속
public class Bus : Vehicle
{
public Bus() : base(6) // Bus는 6개의 바퀴를 가짐
{
}
public override void Start()
{
Console.WriteLine($"Bus with {wheelCount} wheels started.");
}
}
class Program
{
static void Main()
{
Bus myBus = new Bus();
myBus.Start(); // "Bus with 6 wheels started."
myBus.Stop(); // "Vehicle stopped."
}
}
3.3 주 사용처
인터페이스
- 다양한 클래스에서 동일한 기능이 필요할 때: 인터페이스는 다양한 클래스가 동일한 메서드를 구현하도록 강제할 수 있다. 이는 다양한 타입의 객체를 동일한 방식으로 처리할 수 있게 해준다.
- 모듈 간 결합도를 낮추고자 할 때: 인터페이스를 사용하면 구현 세부사항을 숨기고, 인터페이스만을 통해 상호 작용하게 할 수 있다. 이는 코드의 결합도를 낮추고 유연성을 증가시키는 데 유리하다.
- 다중 상속이 필요할 때: C#에서는 클래스가 여러 인터페이스를 구현할 수 있으므로, 하나의 클래스에 여러 기능을 추가하고 싶을 때 유용하다.
추상 클래스
- 공통적인 기본 기능을 제공하고자 할 때: 추상 클래스를 사용하면 일부 메서드 또는 필드를 구현하여 상속받는 클래스에서 이를 사용하거나 확장할 수 있다. 이는 코드 재사용을 촉진한다.
- 상속 구조에서 코드를 공유하고자 할 때: 상속받는 모든 클래스에 공통적인 메서드나 필드가 있다면 추상 클래스에서 이를 구현하여 중복을 최소화할 수 있다.
- 클래스 계층구조에서 엄격한 규칙을 적용하고자 할 때: 추상 클래스는 특정 메서드가 반드시 구현되어야 함을 보장하며, 선택적으로 메서드의 구현을 제공할 수 있다.
'프로그래밍 > C#' 카테고리의 다른 글
[C#] 딕셔너리를 이용한 조건문 리펙토링 (2) | 2024.04.26 |
---|