C#에서 추상화는 주로 추상 클래스와 인터페이스를 통해 구현됩니다.
1. 개념
추상 클래스 ( Abstract Class )
추상 클래스는 하나 이상의 추상 멤버 (메서드, 속성 등)를 포함할 수 있는 클래스입니다.
추상 멤버는 본체가 없으며 파생 클래스(자식 클래스)에서 반드시 구현되어야 합니다.
일반적인 메서드나 속성도 포함할 수 있습니다.
정의되지 않은 불완전한 ( == 중괄호 { } 가 없는 ) 메서드 (추상 메서드)를 1개라도 포함하고 있는 클래스입니다.
구현은 반드시 파생 클래스(자식 클래스)에서 구현해야 합니다. 가상 메서드 (Virtual Method)와 비슷하지만 반드시 구현해야 하므로 virtual 키워드는 붙이지 않습니다.
[요약]
- 추상 클래스는 하나 이상의 추상 멤버(abstract method, abstract property)를 가지고 있는 클래스입니다.
- 추상 멤버는 선언만 있고, 실제 구현은 없는 메서드 또는 속성을 말합니다.
- 추상 클래스는 직접 객체를 생성할 수 없으며, 반드시 상속하여 사용해야 합니다.
[추상 멤버]
- 추상 클래스는 일반 메서드와 속성 뿐만 아니라, 추상 메서드와 추상 속성도 포함할 수 있습니다.
- 추상 메서드와 속성은 파생 클래스(자식 클래스)에서 반드시 구현되어야 합니다.
2. 형식
abstract class Shape
{
// 추상 메서드
public abstract void Draw();
// 일반 메서드
public void Resize()
{
Console.WriteLine("Resizing the shape.");
}
// 추상 속성
public abstract int Area { get; }
}
추상 클래스 Shape은 Draw라는 추상 메서드, Resize라는 일반 메서드, 그리고 Area라는 추상 속성을 가지고 있습니다.
3. 상속 및 구현
class Circle : Shape
{
private int radius;
public Circle(int r)
{
radius = r;
}
// 추상 메서드의 구현
public override void Draw()
{
Console.WriteLine("Drawing a circle.");
}
// 추상 속성의 구현
public override int Area
{
get { return (int)(Math.PI * radius * radius); }
}
}
Circle 클래스는 Shape 클래스를 상속받았고, 추상 클래스의 추상 메서드인 Draw와 추상 속성인 Area를 반드시 구현해야 합니다. 여기서 일반메서드인 Resize 메서드는 구현하지 않아도 됩니다.
4. 사용 예
Shape myShape = new Circle(5);
myShape.Draw(); // Circle 클래스의 Draw 메서드 호출
myShape.Resize(); // Shape 클래스의 Resize 메서드 호출
int area = myShape.Area; // Circle 클래스의 Area 속성 호출
Shape 클래스의 인스턴스를 Circle 클래스로 생성했습니다.
이렇게 생성한 객체는 Shape 형식으로 선언되었기 때문에 Draw, Resize, Area 등의 메서드와 속성에 접근할 수 있습니다.
Draw 메서드는 Circle 클래스의 구현이 호출되고, Resize 메서드는 Shape 클래스의 구현이 호출됩니다.
5. 주의사항
- 추상 클래스는 직접 객체를 생성할 수 없으므로 추상 클래스 타입의 변수로 파생 클래스의 객체를 참조할 수 있습니다.
- 추상 클래스는 반드시 상속 후에 사용되어야 하며, 파생 클래스에서 추상 멤버를 반드시 구현해야 합니다.
- 추상 클래스 내에서는 일반 메서드를 가질 수 있습니다.
- 파생 클래스에서 추상 멤버를 구현하지 않으면, 그 파생 클래스도 추상 클래스로 선언되어야 합니다.
다시 말해, 추상 클래스에 있는 모든 추상 멤버는 파생 클래스에서 반드시 구현되어야 하며, 만약 구현되지 않으면 그 클래스는 추상클래스로 선언되어야 합니다.
6. 장점
- 공통된 기능을 추상 클래스에 구현함으로써 코드 중복을 피할 수 있습니다.
- 파생 클래스에서 특정 동작을 강제하고, 다형성을 지원하여 유연한 구조를 제공합니다.
- 인터페이스와 함께 사용하여 다중 상속을 구현할 수 있습니다.
추상 클래스는 일반 클래스와 달리 인스턴스를 직접 생성할 수 없고, 파생 클래스를 통해 사용되므로 상속 과계에서 코드의 일관성과 유지보수성을 높이는 데 도움이 됩니다.
추상 클래스를 사용하면 공통된 동작을 가진 클래스를 일반화하여 코드의 재사용성을 높일 수 있습니다. 상속을 통해 특정 동작을 강제하고, 다형성을 지원하여 유연한 구조를 제공할 수 있습니다.
인터페이스 ( Interface )
1. 개념
인터페이스는 C#에서 여러 클래스 간에 공통된 동작을 정의하고 다중 상속을 지원하기 위한 도구입니다.
- 인터페이스는 추상 메서드, 속성, 이벤트 등의 추상 멤버들로만 구성된 추상 형식입니다.
- 클래스가 인터페이스를 구현하면, 해당 클래스는 인터페이스에 정의된 모든 멤버를 구현해야 합니다.
2. 형식
interface IDrawable
{
void Draw(); // 추상 메서드
}
interface IMovable
{
void Move(); // 추상 메서드
}
* 인터페이스의 이름은 통상 이름앞에 대문자 I 를 사용합니다.
인터페이스는 interface 키워드를 사용하여 정의되며, 추상 메서드를 선언합니다. 여기서는 IDrawable과 IMovable이라는 두 개의 인터페이스를 정의했습니다.
3. 구현
클래스에서 인터페이스를 구현할 때는 class 키워드 뒤에 콜론(:)을 사용하여 구현합니다.
구현되어야 하는 각 메서드에 대해 public 접근 제한자를 사용하고, 메서드 바디 대신 세미콜론(;)을 사용하여 추상 메서드임을 표시합니다.
class Circle : IDrawable, IMovable
{
private int radius;
public Circle(int r)
{
radius = r;
}
public void Draw()
{
Console.WriteLine("Drawing a circle.");
}
public void Move()
{
Console.WriteLine("Moving the circle.");
}
}
위의 코드에서 Circle 클래스는 IDrawable과 IMovable 인터페이스를 모두 구현하고 있습니다.
Draw 메서드와 Move 메서드를 구현하여 인터페이스에서 정의한 추상 메서드에 대한 실제 동작을 제공하고 있습니다.
4. 사용 예
Circle myCircle = new Circle(5);
myCircle.Draw(); // IDrawable 인터페이스의 Draw 메서드 호출
myCircle.Move(); // IMovable 인터페이스의 Move 메서드 호출
Circle 클래스의 인스턴스를 생성하고, 이를 통해 IDrawable과 IMovable 인터페이스의 메서드를 호출할 수 있습니다. 이렇게 인터페이스를 구현함으로써, 여러 클래스가 동일한 메서드 이름을 사용하면서도 각각의 특별한 동작을 수행할 수 있습니다.
5. 주의사항
- 클래스는 여러 개의 인터페이스를 동시에 구현할 수 있습니다.
- 인터페이스는 다중 상속을 지원하므로, 여러 인터페이스의 특성을 하나의 클래스에서 모두 사용할 수 있습니다.
- 인터페이스는 클래스의 행동을 정의하고 클래스 간에 표준을 제공하는 데 사용됩니다.
6. 장점
- 다중 상속의 대안: C#에서는 클래스가 다중 클래스 상속을 지원하지 않지만, 여러 개의 인터페이스를 구현할 수 있습니다. 클래스가 여러 인터페이스를 구현함으로써, 다양한 특성을 갖추게 됩니다.
- 유연한 설계: 인터페이스를 사용하면 클래스 간의 결합도를 낮추고, 각 클래스를 독립적으로 변경하거나 확장할 수 있습니다. 이는 소프트웨어의 유연성을 향상시킵니다.
- 표준화된 규약 제공: 인터페이스는 일종의 계약(contract)으로서, 해당 인터페이스를 구현한 클래스들은 특정한 규약을 따르게 됩니다. 이를 통해 코드의 일관성을 유지하고, 협업에서 표준을 정의할 수 있습니다.
[ 추상클래스와 인터페이스 비교 ]
1. 공통점
본체가 정의되지 않는 (선언만 있고 구현내용이 없는) 추상 메서드만 갖습니다.
구체적인 구현은 숨기고, 공통된 기능을 정의합니다.
- 추상 멤버를 가질 수 있다: 추상 클래스와 인터페이스는 모두 추상 멤버(추상 메서드, 속성 등)를 가질 수 있습니다. 이는 파생 클래스 또는 구현 클래스에서 반드시 구현되어야 합니다.
- 다형성을 제공한다: 추상 클래스와 인터페이스는 다형성을 지원하여, 같은 타입으로 여러 클래스 또는 구현체를 다룰 수 있게 합니다.
- 객체 지향 프로그래밍(OOP)의 핵심 개념: 추상 클래스와 인터페이스는 객체 지향 프로그래밍에서 추상화를 통해 코드의 재사용성을 높이고, 코드를 구조화하는 데 사용됩니다.
2. 차이점
추상클래스는 인스턴스를 직접 생성할 수 없고, 추상 클래스의 인스턴스를 만들기 위해서는 이 클래스를 상속받은 파생클래스를 생성하고, 그 클래스의 인스턴스를 생성해야 합니다.
인터페이스는 인스턴스를 직접 생성할 수 없고, 구현이 필요한 멤버들을 선언할 뿐입니다.
추상클래스는 추상 메서드를 선택적으로 가지는데 비해, 인터페이스는 전부 추상메소드만 가집니다.
그래서 인터페이스를 상속한 클래스는 메소드를 전부 구현해야 합니다.
2.1 구현 유무:
- 추상 클래스: 일반 메서드 또는 속성 등을 구현할 수 있습니다. 추상 클래스는 일부 구현된 멤버를 가질 수 있습니다.
- 인터페이스: 추상 멤버만을 가지며, 멤버의 구현이 없습니다. 클래스는 인터페이스를 구현할 때 모든 멤버를 구현해야 합니다.
2.2 다중 상속:
- 추상 클래스: C#에서는 클래스가 하나의 클래스만을 상속할 수 있습니다. 다중 상속을 지원하지 않습니다.
- 인터페이스: 여러 개의 인터페이스를 구현함으로써 다중 상속과 유사한 효과를 얻을 수 있습니다.
2.3 생성자의 존재:
- 추상 클래스: 생성자를 가질 수 있으며, 객체를 초기화하는 역할을 수행할 수 있습니다.
- 인터페이스: 생성자를 가질 수 없습니다. 객체의 초기화에 관련된 작업을 수행할 수 없습니다.
2.4 접근 한정자 사용:
- 추상 클래스: 접근 한정자를 사용하여 멤버의 가시성을 제어할 수 있습니다.
- 인터페이스: 멤버는 기본적으로 public이며, 접근 한정자를 명시하지 않습니다.
2.5 설계 목적:
- 추상 클래스: 코드의 일부를 공유하고, 강제로 구현해야 하는 메서드를 제공하기 위해 사용됩니다.
- 인터페이스: 클래스 간에 공통된 동작을 정의하고, 여러 클래스에 대한 표준을 제공하기 위해 사용됩니다.
[ 간단한 예제를 통해서 쉽게 이해해 보겠습니다. ]
일반적으로 추상 클래스는 서로 다른 클래스 간의 공통된 기능을 구현할 때 사용되고, 인터페이스는 서로 관계없는 클래스 간에 공통된 동작을 정의할 때 사용됩니다.
1. 추상 클래스의 사용 예
// 추상 클래스
abstract class Smartphone
{
// 공통된 기능 - 구현이 있는 메서드
public void PowerOn()
{
Console.WriteLine("Smartphone is powering on.");
}
// 추상 메서드 - 각 회사에서 반드시 구현해야 함
public abstract void Call();
public abstract void SendText();
public abstract void UseInternet();
}
// 추상 클래스를 상속받은 구현 클래스 - Samsung
class SamsungPhone : Smartphone
{
public override void Call()
{
Console.WriteLine("Samsung phone is making a call.");
}
public override void SendText()
{
Console.WriteLine("Sending a text from Samsung phone.");
}
public override void UseInternet()
{
Console.WriteLine("Browsing the internet on Samsung phone.");
}
}
// 추상 클래스를 상속받은 구현 클래스 - Apple
class IPhone : Smartphone
{
public override void Call()
{
Console.WriteLine("iPhone is making a call.");
}
public override void SendText()
{
Console.WriteLine("Sending a text from iPhone.");
}
public override void UseInternet()
{
Console.WriteLine("Browsing the internet on iPhone.");
}
}
위의 예제에서 Smartphone 추상 클래스는 PowerOn이라는 구현이 있는 메서드와 Call, SendText, UseInternet라는 추상 메서드를 정의합니다.
SamsungPhone 클래스와 IPhone 클래스는 각각 Smartphone을 상속받아 추상 메서드를 구현하고 있습니다.
2. 인터페이스 사용 예
// 인터페이스
interface ICommunication
{
void Call();
void SendText();
void UseInternet();
}
// 각 회사에서 인터페이스를 구현하는 클래스
class SamsungPhone : ICommunication
{
public void Call()
{
Console.WriteLine("Samsung phone is making a call.");
}
public void SendText()
{
Console.WriteLine("Sending a text from Samsung phone.");
}
public void UseInternet()
{
Console.WriteLine("Browsing the internet on Samsung phone.");
}
}
class IPhone : ICommunication
{
public void Call()
{
Console.WriteLine("iPhone is making a call.");
}
public void SendText()
{
Console.WriteLine("Sending a text from iPhone.");
}
public void UseInternet()
{
Console.WriteLine("Browsing the internet on iPhone.");
}
}
이번에는 ICommunication 인터페이스를 사용하여 통화, 문자, 인터넷 기능을 정의하고, 각 회사의 스마트폰 클래스에서 이 인터페이스를 구현하는 예제입니다.
SamsungPhone 클래스와 IPhone 클래스는 각각 ICommunication을 구현하여 필요한 기능을 제공합니다.
두 예제는 각각 추상 클래스와 인터페이스를 사용하여 공통된 스마트폰 기능을 정의하고 각 회사에서 이를 구현하는 방법을 보여줍니다.
3. 추상 클래스와 인터페이스의 특징
3.1 추상 클래스의 특징
- 일부 구현이 가능한 멤버 제공: 추상 클래스는 일부 구현이 있는 메서드나 속성을 가질 수 있습니다. PowerOn과 같이 이미 구현이 된 메서드가 있습니다.
- 단일 상속: 클래스는 하나의 추상 클래스만을 상속할 수 있습니다.
- 생성자 존재: 추상 클래스는 생성자를 가질 수 있습니다.
- 필드 및 일반 메서드 정의 가능: 추상 클래스는 필드나 일반 메서드를 포함할 수 있습니다.
3.2 인터페이스의 특징
- 모든 멤버가 추상: 인터페이스는 모든 멤버가 추상이므로 구현이 없습니다. 메서드, 속성, 이벤트 등을 선언만 합니다.
- 다중 상속: 클래스는 여러 개의 인터페이스를 구현할 수 있습니다.
- 생성자 없음: 인터페이스는 생성자를 가질 수 없습니다.
- 멤버의 가시성: 인터페이스의 멤버는 기본적으로 public이며, 가시성을 명시하지 않습니다.
- 추가 기능 제공 가능: 클래스에서 여러 인터페이스를 구현하여 여러 기능을 추가로 제공할 수 있습니다.
위의 차이점을 기반으로 스마트폰 예제에서는 추상 클래스가 이미 구현된 PowerOn 메서드를 가지고 있고, 생성자도 존재합니다. 인터페이스는 모든 메서드가 추상이며 생성자가 없습니다. 클래스에서는 여러 인터페이스를 구현하여 다양한 기능을 추가할 수 있습니다.
4. 추상 클래스와 인터페이스 사용 이점
4.1 추상 클래스의 이점
- 부분적인 구현 제공: 추상 클래스는 일부 메서드를 구현할 수 있기 때문에, 공통된 로직을 추상 클래스에서 구현하고 파생 클래스에서는 특화된 부분만 구현할 수 있습니다. 예를 들어, 모든 스마트폰이 공통으로 가져야 하는 PowerOn 메서드를 구현할 수 있습니다.
- 공통 필드와 메서드 제공: 추상 클래스는 필드와 메서드를 가질 수 있어서, 공통된 필드나 메서드를 제공하여 코드의 재사용성을 높일 수 있습니다.
- 단일 상속: 추상 클래스는 하나의 클래스만을 상속받을 수 있습니다. 이는 클래스 간의 강력한 관계를 형성할 수 있습니다.
4.2 인터페이스의 이점
- 다중 상속: 인터페이스는 여러 개의 인터페이스를 구현할 수 있습니다. 클래스가 다양한 동작을 수행해야 할 때, 인터페이스를 통해 다중 상속과 유사한 효과를 얻을 수 있습니다. 각 회사에서 제공하는 다양한 기능을 하나의 클래스에서 구현할 수 있습니다.
- 유연한 설계: 인터페이스는 클래스 간에 결합도를 낮추어 유연한 설계를 가능하게 합니다. 각 클래스는 필요에 따라 인터페이스를 구현하여 필요한 동작을 정의할 수 있습니다.
- 표준화된 규약 제공: 인터페이스는 특정한 규약을 정의하여 해당 규약을 따르는 클래스는 특정한 동작을 보장합니다. 이는 협업이나 라이브러리 개발에서 표준을 제공하는 데 도움이 됩니다.
4.3 사용 예제에 기반한 이점
4.3.1 추상 클래스 사용 이점:
- Smartphone 추상 클래스에서 PowerOn 메서드를 구현하여 모든 스마트폰에서 필요한 초기화 로직을 제공할 수 있습니다.
- Smartphone 클래스의 필드를 통해 공통된 데이터를 저장하고, 이를 상속받는 클래스에서 공유할 수 있습니다.
4.3.2 인터페이스 사용 이점:
- ICommunication 인터페이스를 통해 각 스마트폰이 Call, SendText, UseInternet라는 공통된 동작을 가지게 하여, 클래스 간에 표준을 제공합니다.
- 각 스마트폰 회사는 ICommunication 인터페이스를 구현하여 독립적으로 기능을 추가할 수 있습니다.
추상 클래스와 인터페이스는 C#에서 객체 지향 프로그래밍에서 중요한 개념 중 하나입니다.
이들은 코드의 재사용성과 유연성을 높이는데 기여하며, 특히 다양한 클래스 간의 관계를 정의하고 코드의 일관성을 유지하는 데 중요한 역할을 합니다.
추상 클래스는 부분적인 구현을 제공함으로써 공통된 로직을 추상화하고, 단일 상속을 통해 클래스 간의 강력한 관계를 형성합니다. 이는 코드의 구조를 일관되게 유지하고 재사용 가능한 코드를 작성하는 데 도움이 됩니다.
인터페이스는 클래스 간의 결합도를 낮추고, 다중 상속을 통해 여러 개의 인터페이스를 구현할 수 있어 유연한 설계를 가능케 합니다. 특히 표준화된 규약을 제공하여 클래스 간의 통일된 동작을 정의하는 데 사용됩니다.
이러한 개념들은 프로그램의 확장성과 유지보수성을 향상시키는데 기여하며, 팀 프로젝트에서 협업 시 일관성 있는 코드를 작성하는데 큰 도움을 줍니다. 따라서 C#에서는 추상 클래스와 인터페이스를 적절히 활용하여 객체 지향적인 설계를 할 수 있도록 고려하는 것이 중요합니다.
'Programming' 카테고리의 다른 글
콜백 메서드 : 쉽고 재미있는 C# Programming 의 기본 (0) | 2024.01.22 |
---|---|
델리게이트 : 쉽고 재미있는 C# Programming 의 기본 (0) | 2024.01.19 |
생성자와 접근지정자 : 쉽고 재미있는 C# Programming 의 기본 (0) | 2024.01.17 |
가상 메서드와 다형성 : 쉽고 재미있는 C# Programming 의 기본 (0) | 2024.01.15 |
객체와 클래스,네임스페이스 : 쉽고 재미있는 C# Programming 의 기본 (0) | 2024.01.15 |