오늘은 기초적이지만 중요한 부분들에 대해서 정리하는 시간을 가져볼것이다.
아는 내용이더라도 다시한번 정리하며, 정확한 개념을 정리해보겠다.
1. 객체와 클래스
객체(Object): 현실 세계의 사물이나 개념을 소프트웨어적으로 표현한 것. 객체는 속성(데이터)과 행동(메서드)를 가짐
클래스(Class): 객체를 생성하기 위한 설계도. 클래스에서 정의된 구조를 바탕으로 실제 데이터를 가진 객체를 만듦
이를 통해 반복되는 코드를 줄이고, 재사용성과 확장성을 높일 수 있음. 즉, 클래스를 바탕으로 동일한 구조를 가진 여러 객체를 만들어 내며, 필요한 기능을 쉽게 추가하거나 유지보수할 수 있게 됨.
// Car 클래스 정의
public class Car
{
// Model이라는 데이터
public string Model;
// Drive라는 해동
public void Drive()
{
Console.WriteLine($"{Model} is driving.");
}
}
// 객체 생성
Car myCar = new Car();
// Model이라는 데이터에 "Tesla"를 넣어줌
myCar.Model = "Tesla";
// Tesla라는 데이터를 가진 Car객체가 Drive라는 행동을 해서 나온 결과
myCar.Drive(); // 출력: Tesla is driving.
2. 생성자
생성자(Constructor): 객체가 생성될 때 자동으로 호출되어 초기값 설정 및 준비 작업을 담당함.
왜 쓰는가 ?
생성자를 통해 객체가 유효한 상태를 가진 채로 시작하도록 할 수 있으며, 이는 이후 코드가 예측 가능하고 안정적으로 동작하는 기반이 됨. 객체 사용 전 기본 세팅을 자동화 하여 실수를 줄이고 유지보수를 용이하게 함
// 클래스 정의
public class Player
{
public string Name;
public int Health;
// 생성자 정의
public Player(string name, int health)
{
Name = name;
Health = health;
}
}
// 객체 생성
Player hero = new Player("Knight", 100);
// 객체 생성 시 바로 이름과 체력을 세팅해 안정적인 시작 상태를 가짐
3. 접근제한자
접근제한자(Access Modifier): 클래스나 멤버(필드, 메서드)에 대한 접근 범위를 제어함. public, private, protected 등의 키워드를 사용함.
왜 필요한가 ?
불필요한 외부 접근을 막아 안정성과 보안성을 높이고, 내부 구현을 숨기며, 코드 변경 시 외부 코드 영향 최소화를 가능하게 함. 이를 통해 모듈성, 캡슐화, 유지보수성을 향상시킴
public class Enemy
{
private int health = 50; // 외부에서 직접 수정 불가
public void TakeDamage(int damage)
{
health -= damage;
Console.WriteLine("적 체력: " + health);
}
}
Enemy goblin = new Enemy();
// goblin.health = 10; // 불가능
goblin.TakeDamage(10); // 메서드를 통해서만 체력 감소
4. Static
static 키워드는 객체의 생성 없이도 접근 가능한 변수나 메서드를 정의함.
왜 쓰는가?
모든 인스턴스가 공유해야하는 데이터나 유틸리티 메서드를 제공하여 메모리 사용을 효율화 하고, 전역적으로 일관성 있는 기능을 지원함. 이를 통해 전역 상태 관리나 공통 기능 제공이 쉬워짐
public static class MathUtils
{
public static int Add(int a, int b)
{
return a + b;
}
}
int sum = MathUtils.Add(3, 4);
// MathUtils 클래스의 인스턴스 없이 바로 호출 가능
5. SOLID 원칙
SOLID 원칙은 객체지향 설계의 모범 사례로, 유지보수성과 확장성을 높이기 위해 제안된 다섯가지 원칙임.
(여기서는 간단하게 요약만 하겠음)
- 단일책임원칙: 한 클래스는 한가지 책임만 가짐. 코드 명확성과 유지보수성 향상
- 개방-폐쇄 원칙: 확장에는 열려있고, 수정에는 닫혀있음. 기능 추가 시 기존 코드 최소 수정
- 리스코프 치환 원칙: 자식 클래스는 부모 클래스를 대체 가능함. 상속 관계의 일관성 유지
- 인터페이스 분리 원칙: 클라이언트가 사용하지 않는 인터페이스에 의존하지 않음. 불필요한 의존성 최소화
- 의존 역전 원칙: 고수준 모듈은 저수준 모듈에 의존하지 않음. 추상화에 의존하여 유연성 확보
이를 통해 코드 구조가 명확해지고 변경에 유연하며, 협업과 유지보수가 쉬워짐.
6. 다형성
다형성(Polymorphism): 다형성은 같은 인터페이스나 부모 클래스를 통해 다른 구현체가 서로 다른 동작을 할 수 있게 하는 특징임.
왜 쓰는가?
이를 활용하면 객체 교체와 기능 확장이 쉬워지고, 코드 구조가 유연해져 새로운 기능을 추가하거나 기존 기능을 변경하기 수월해짐.
public abstract class Animal
{
public abstract void Speak();
}
public class Dog : Animal
{
public override void Speak() { Console.WriteLine("멍멍!"); }
}
public class Cat : Animal
{
public override void Speak() { Console.WriteLine("야옹!"); }
}
Animal pet = new Dog();
pet.Speak(); // "멍멍!"
pet = new Cat();
pet.Speak(); // "야옹!"