2024. 1. 4. 21:03ㆍ내일배움캠프
오늘은 C#학습의 마무리 단계이다. 정리할께 쏟아져나와서 참 머리가 아프다.
하지만 열심히 정리해보자.
인터페이스
인터페이스를 사용하는 이유는 다음과 같다.
- 코드의 재사용성: 인터페이스를 사용하면 다른 클래스에서 해당 인터페이스를 구현하여 동일한 기능을 공유할 수 있다. 인터페이스를 통해 다양한 클래스가 동일한 동작을 수행할 수 있으므로 코드의 재사용성이 향상된다.
- 다중 상속 제공: C#에서는 클래스는 단일 상속만을 지원하지만, 인터페이스는 다중 상속을 지원한다. 클래스가 여러 인터페이스를 구현함으로써 여러 개의 기능을 조합할 수 있습니다. 다중 상속을 통해 클래스는 더 다양한 동작을 수행할 수 있다.
- 유연한 설계: 인터페이스를 사용하면 클래스와 인터페이스 간에 느슨한 결합을 형성할 수 있다. 클래스는 인터페이스를 구현하기만 하면 되므로, 클래스의 내부 구현에 대한 변경 없이 인터페이스의 동작을 변경하거나 새로운 인터페이스를 추가할 수 있다. 이는 유연하고 확장 가능한 소프트웨어 설계를 가능하게 한다.
C#에서는 클래스는 다중 상속을 지원하지 않지만 인터페이스는 다중 상속을 지원하고 있다.
왜 클래스에서는 다중 상속을 지원하지 않는지 살펴보자.
- 다이아몬드 문제(Diamond Problem): 다중 상속을 허용하면 한 클래스가 두 개 이상의 부모 클래스로부터 동일한 멤버를 상속받을 수 있습니다. 이 경우, 같은 이름의 멤버를 가지고 있을 때 어떤 부모 클래스의 멤버를 사용해야 하는지 모호해집니다. 이런 모호성을 해결하기 위한 규칙이 필요하게 되는데, 이로 인해 코드가 복잡해지고 가독성이 저하될 수 있습니다.
- 설계의 복잡성 증가: 다중 상속을 허용하면 클래스 간의 관계가 복잡해집니다. 클래스가 다중 상속을 받을 경우, 어떤 클래스로부터 어떤 멤버를 상속받을지 결정해야 합니다. 이로 인해 클래스 간의 상속 관계를 파악하기 어려워지고 코드의 유지 보수성이 저하될 수 있습니다.
- 이름 충돌과 충돌 해결의 어려움: 다중 상속을 허용하면 여러 부모 클래스로부터 상속받은 멤버들이 이름이 충돌할 수 있습니다. 이러한 충돌을 해결하기 위해 충돌하는 멤버를 재정의해야 하거나 명시적으로 부모 클래스를 지정해야 할 수 있습니다. 이는 코드의 복잡성을 증가시키고 오류 발생 가능성을 높입니다.
- 설계의 일관성과 단순성 유지: C#은 단일 상속을 통해 설계의 일관성과 단순성을 유지하고자 합니다. 단일 상속을 통해 클래스 간의 관계를 명확하게 만들고 코드의 가독성과 이해도를 높일 수 있습니다. 또한 인터페이스를 사용하여 다중 상속이 필요한 경우에도 유사한 기능을 구현할 수 있습니다.
그렇다면 인터페이스의 특징과 구현 방법에 대해 알아보자
- 인터페이스란 클래스가 구현해야 하는 멤버들을 정의하는 것.
- 인터페이스는 클래스의 일종이 아니며, 클래스에 대한 제약 조건을 명시하는 것.
- 클래스가 인터페이스를 구현할 경우, 모든 인터페이스 멤버를 구현해야 한다.
- 인터페이스는 다중 상속을 지원한다.
-인터페이스의 구현-
public interface IMovable
{
void Move(int x, int y); // 이동 메서드 선언
}
public class Player : IMovable
{
public void Move(int x, int y)
{
// 플레이어의 이동 구현
}
}
public class Enemy : IMovable
{
public void Move(int x, int y)
{
// 적의 이동 구현
}
}
사용법을 보니 느낌이 딱 온다.
플레이어와 적이 공통적으로 갖는 이동 메서드를 인터페이스로 정의해두고
클래스에 상속해서 각자 인터페이스를 구현하는 예시이다.
인터페이스와 추상클래스
인터페이스의 특징과 장단점:
- 인터페이스는 추상적인 동작만 정의하고, 구현을 갖지 않습니다.
- 다중 상속이 가능하며, 여러 클래스가 동일한 인터페이스를 구현할 수 있습니다.
- 클래스들 간의 결합도를 낮추고, 유연한 상호작용을 가능하게 합니다.
- 코드의 재사용성과 확장성을 향상시킵니다.
- 단점으로는 인터페이스를 구현하는 클래스가 모든 동작을 구현해야 한다는 의무를 가지기 때문에 작업량이 증가할 수 있습니다.
추상 클래스의 특징과 장단점:
- 추상 클래스는 일부 동작의 구현을 가지며, 추상 메서드를 포함할 수 있습니다.
- 단일 상속만 가능하며, 다른 클래스와 함께 상속 계층 구조를 형성할 수 있습니다.
- 공통된 동작을 추상화하여 코드의 중복을 방지하고, 확장성을 제공합니다.
- 구현된 동작을 가지고 있기 때문에, 하위 클래스에서 재정의하지 않아도 될 경우 유용합니다.
- 단점으로는 다중 상속이 불가능하고, 상속을 통해 밀접하게 결합된 클래스들을 형성하므로 유연성이 제한될 수 있습니다.
열거형
열거형?
열거형이란 쉽게 말해 특정 정수값에 별명을 붙여 사용하는 것이다.
사용하는 이유
- 가독성: 열거형을 사용하면 일련의 연관된 상수들을 명명할 수 있다. 이를 통해 코드의 가독성이 향상되고, 상수를 사용할 때 실수로 잘못된 값을 할당하는 것을 방지할 수 있다.
- 자기 문서화(Self-documenting): 열거형은 의미 있는 이름을 사용하여 상수를 명명할 수 있다. 이를 통해 코드의 가독성이 향상되며, 상수의 의미를 명확하게 설명할 수 있다.
- 스위치 문과의 호환성: 열거형은 스위치 문과 함께 사용될 때 유용하다. 열거형을 사용하면 스위치 문에서 다양한 상수 값에 대한 분기를 쉽게 작성할 수 있다.
열거형 특징
- 열거형은 서로 관련된 상수들의 집합을 정의할 때 사용됩니다.
- 열거형의 각 상수는 정수 값으로 지정됩니다.
열거형 구현
// 월 열거형
public enum Month
{
January = 1,
February,
March,
April,
May,
June,
July,
August,
September,
October,
November,
December
}
// 처리하는 함수
static void ProcessMonth(int month)
{
if (month >= (int)Month.January && month <= (int)Month.December)
{
Month selectedMonth = (Month)month;
Console.WriteLine("선택한 월은 {0}입니다.", selectedMonth);
// 월에 따른 처리 로직 추가
}
else
{
Console.WriteLine("올바른 월을 입력해주세요.");
}
}
// 실행 예제
static void Main()
{
int userInput = 7; // 사용자 입력 예시
ProcessMonth(userInput);
}
델리게이트
델리게이트?
- 델리게이트(delegate)는 메서드를 참조하는 타입이다.
- 다른 프로그래밍 언어에서는 함수 포인터라는 용어를 사용하기도 한다.
- 델리게이트를 이용하면 메서드를 매개변수로 전달하거나 변수에 할당할 수 있다.
델리게이트 구현
delegate int Calculate(int x, int y);
static int Add(int x, int y)
{
return x + y;
}
class Program
{
static void Main()
{
// 메서드 등록
Calculate calc = Add;
// 델리게이트 사용
int result = calc(3, 5);
Console.WriteLine("결과: " + result);
}
}
람다
람다?
- 람다(lambda)는 익명 메서드를 만드는 방법이다.
- 람다를 사용하면 메서드의 이름 없이 메서드를 만들 수 있다.
- 람다는 델리게이트를 사용하여 변수에 할당하거나, 메서드의 매개변수로 전달할 수 있다.
(parameter_list) => expression
Calculate calc = (x, y) =>
{
return x + y;
};
Calculate calc = (x, y) => x + y;
Func 과 Action
Func / Anction?
- Func과 Action은 델리게이트를 대체하는 미리 정의된 제네릭 형식이다.
- Func는 값을 반환하는 메서드를 나타내는 델리게이트이다. 마지막 제네릭 형식 매개변수는 반환 타입을 나타낸다. 예를 들어, Func<int, string>는 int를 입력으로 받아 string을 반환하는 메서드를 나타낸다.
- Action은 값을 반환하지 않는 메서드를 나타내는 델리게이트이다. Action은 매개변수를 받아들이지만, 반환 타입이 없다. 예를 들어, Action<int, string>은 int와 string을 입력으로 받고, 아무런 값을 반환하지 않는 메서드를 나타낸다.
- Func 및 Action은 제네릭 형식으로 미리 정의되어 있어 매개변수와 반환 타입을 간결하게 표현할 수 있다.
Func 구현
// Func를 사용하여 두 개의 정수를 더하는 메서드
int Add(int x, int y)
{
return x + y;
}
// Func를 이용한 메서드 호출
Func<int, int, int> addFunc = Add;
int result = addFunc(3, 5);
Console.WriteLine("결과: " + result);
Action 구현
// Action을 사용하여 문자열을 출력하는 메서드
void PrintMessage(string message)
{
Console.WriteLine(message);
}
// Action을 이용한 메서드 호출
Action<string> printAction = PrintMessage;
printAction("Hello, World!");
LINQ
LINQ?
- .NET 프레임워크에서 제공되는 쿼리 언어 확장
- 데이터 소스(예: 컬렉션, 데이터베이스, XML 문서 등)에서 데이터를 쿼리하고 조작하는데 사용된다.
- 데이터베이스 쿼리와 유사한 방식으로 데이터를 필터링, 정렬, 그룹화, 조인 등 다양한 작업을 수행할 수 있다.
- LINQ는 객체, 데이터베이스, XML 문서 등 다양한 데이터 소스를 지원한다.
LINQ 구조
var result = from 변수 in 데이터소스
[where 조건식]
[orderby 정렬식 [, 정렬식...]]
[select 식];
- var 키워드는 결과 값의 자료형을 자동으로 추론합니다.
- from 절에서는 데이터 소스를 지정합니다.
- where 절은 선택적으로 사용하며, 조건식을 지정하여 데이터를 필터링합니다.
- orderby 절은 선택적으로 사용하며, 정렬 방식을 지정합니다.
- select 절은 선택적으로 사용하며, 조회할 데이터를 지정합니다.
중간중간엔 무슨 내용인지 몰라서 한참 다시 읽어보고 예제도 직접 써보고 하느라 시간이 너무 오래걸렸다.
알고 있었던 내용부터 몰랐던 내용까지 한번 쭈욱 살펴봤는데
처음엔 괜찮아지만 후반부에 들어서면서 정말 머리가 터질것 같았다. 아직도 이해를 못하고 있는 부분도 있고
240104-TIL은 여기서 마치도록 하겠다.
앗 내일은 그간 배운 C#을 활용해 Text로 게임을 만드는 과제와 함께 돌아오겠다.
'내일배움캠프' 카테고리의 다른 글
240108-TIL (0) | 2024.01.08 |
---|---|
240105-TIL (0) | 2024.01.05 |
240103-TIL (0) | 2024.01.03 |
240102-TIL (0) | 2024.01.02 |
231229-TIL (0) | 2023.12.29 |