객체지향 프로그래밍(Object-Oriented Programming, OOP)
컴퓨터 프로그래밍의 패러다임 중 하나.
프로그램을 "객체"라는 기본 단위로 나누고 이 객체들 간의 상호작용을 중심으로 프로그래밍하는 접근 방식.
특징
캡슐화 (Encapsulation) : 객체 내부의 데이터와 기능(메서드)을 하나의 단위로 묶는 것.
객체의 내부 구조를 숨기고, 외부에서 직접적인 접근을 제한함으로써 안정성과 유지보수성을 높임.
상속 (Inheritance) : 클래스들 사이에 계층 구조를 만들어서, 부모 클래스의 특성과 기능을 자식 클래스가 물려받아 사용하는 개념.
코드 재사용성을 높이고, 유사한 클래스들을 쉽게 관리가능.
다형성 (Polymorphism) : 하나의 인터페이스나 기능을 다양한 방식으로 구현하거나 사용할 수 있는 능력.
오버로딩과 오버라이딩을 통해 구현하고 유연하고 확장 가능한 코드 작성할 수 있게 하며, 코드의 가독성과 재사용성을 높임.
추상화 (Abstraction) : 복잡한 현실 세계의 개념을 단순화하여 모델링하는 것을 의미.
클래스와 인터페이스를 정의함으로써 필요한 기능에만 집중하고 불필요한 세부 사항을 무시.
객체
객체지향 프로그래밍(OOP)에서 프로그램의 기본 단위.
클래스의 실체화된 형태, 클래스로부터 생성되며, 객체마다 고유한 데이터를 가짐.
클래스
객체를 생성하기 위한 템플릿이며, 객체의 특성(속성)과 기능(메서드)을 정의하는 일종의 설계도.
클래스는 속성과 동작을 가지며, 속성은 필드로, 동작은 메서드로 표현.
객체를 생성하기 위해서는 클래스를 사용하여 인스턴스를 만들어야 함.
클래스의 구성 요소
필드 (Fields): 클래스에서 사용되는 변수, 객체의 상태를 나타내는 데이터를 저장하기 위해 사용.
메서드 (Methods): 클래스에서의 동작 정의, 객체의 동작을 구현하기 위해 사용.
생성자 (Constructors): 객체를 초기화하는 역할, 객체가 생성될 때 자동으로 호출되며, 필드를 초기화하는 등의 작업을 수행.
소멸자 (Destructors): 객체가 소멸될 때 호출, 메모리나 리소스의 해제 등의 작업을 수행.
프로퍼티 (Property)
클래스 멤버로서, 멤버 변수에 접근하고 설정하는 메커니즘을 제공하는 요소.
멤버 변수의 값을 읽거나 변경할 때, 내부적으로는 메서드 호출을 통해 값을 처리.
데이터 은닉과 보안을 강화하며, 값에 대한 유효성 검사, 계산 등을 수행할 수 있게 함.
프로퍼티 구문
[접근 제한자] [데이터 타입] 프로퍼티명 { get { // 필드를 반환하거나 다른 로직 수행 } set { // 필드에 값을 설정하거나 다른 로직 수행 } }
자동 프로퍼티 : 프로퍼티를 간단하게 정의하고 사용할 수 있는 편리한 기능
[접근 제한자] [데이터 타입] 프로퍼티명 { get; set; }
상속(Inheritance)
하위 클래스(또는 파생 클래스)가 상위 클래스(또는 기본 클래스 또는 부모 클래스)의 특성과 동작을 물려받는 개념.
코드 재사용성을 높이고, 클래스 간의 계층 구조를 형성하여 객체들을 논리적으로 그룹화하고 관리함.
상속의 특징
자식 클래스는 상속받은 부모 클래스의 멤버에 접근할 수 있으며, 이를 통해 부모 클래스의 기능을 재사용할 수 있음.
자식 클래스는 부모 클래스의 메서드를 재정의하여 자신에게 맞게 수정할 수 있음.
부모 클래스가 또 다른 클래스의 자식 클래스가 될 수 있으며, 이를 통해 상속의 계층 구조를 형성.
상속의 종류
단일 상속: 하나의 자식 클래스가 하나의 부모 클래스만 상속받는 것.
다중 상속: 하나의 자식 클래스가 여러 개의 부모 클래스를 동시에 상속받는 것.
C#은 다중 상속을 지원하지 않음.
인터페이스 상속: 클래스가 인터페이스를 상속받는 것.
인터페이스는 다중 상속을 지원하며, 클래스는 하나의 클래스와 여러 개의 인터페이스를 동시에 상속받을 수 있음.
다형성(Polymorphism)
하나의 인터페이스나 메서드를 여러 다른 방식으로 구현하거나 활용할 수 있는 능력을 의미.
코드의 재사용성, 유연성, 확장성을 높이며, 객체들 간의 상호작용을 간단하게 함.
가상(Virtual) 메서드
기본적으로 부모 클래스에서 정의되고 하위 클래스에서 재정의(오버라이딩)될 수 있는 메서드.
virtual
키워드를 사용.
class Animal // 부모클래스 { public virtual void MakeSound() { Console.WriteLine("Animal makes a sound."); } } class Dog : Animal // 자식(Dog) 클래스 { public override void MakeSound() { Console.WriteLine("Dog barks."); } } class Cat : Animal // 자식(Cat) 클래스 { public override void MakeSound() { Console.WriteLine("Cat meows."); } } class Program { static void Main(string[] args) { Animal animal1 = new Dog(); Animal animal2 = new Cat(); animal1.MakeSound(); // 출력: "Dog barks." animal2.MakeSound(); // 출력: "Cat meows." } }
추상(Abstract) 클래스
추상 클래스는 하나 이상의 추상 메서드를 가지는 클래스로, 이 메서드들은 선언만 있고 구현은 없음.
추상 클래스는 인스턴스화될 수 없고, 하위 클래스에서 반드시 구현되어야 하는 메서드를 강제하는 역할.
abstract
키워드를 사용하여 선언되며, 추상 메서드를 포함할 수 있음.
추상 메서드
추상 메서드는 메서드의 선언만 있고 본체(구현)가 없는 메서드.
추상 메서드는 반드시 추상 클래스 내에서 선언되어야 하며, 하위 클래스에서 반드시 구현되어야 함.
abstract class Shape // 추상 클래스 { public abstract double CalculateArea(); // 추상 메서드 public void Display() { Console.WriteLine("Displaying shape."); } } class Circle : Shape // 하위 클래스 { private double radius; public Circle(double r) { radius = r; } public override double CalculateArea() { return Math.PI * radius * radius; } }
제너릭(Generic)
다양한 데이터 타입에 대해 재사용 가능한 클래스, 인터페이스, 메서드 등을 작성하기 위한 기능.
제너릭을 사용하면 데이터 타입을 미리 지정하지 않고, 실제 사용할 때 타입을 지정하여 사용할 수 있음.
코드의 재사용성과 타입 안정성을 향상.
C#에서는 <T>
형태의 키워드를 이용하여 제너릭을 선언.
out, ref 키워드
out, ref 키워드는 메서드에서 매개변수를 전달할 때 사용.
out, ref 키워드를 사용하면 메서드에서 값을 반환하는 것이 아니라, 매개변수를 이용하여 값을 전달할 수 있음.
ref 키워드는 메서드에 매개변수를 전달할 때 값을 복사하지 않고 원래 변수의 참조를 전달
void ModifyValue(ref int x) { x = 10; } int number = 5; ModifyValue(ref number); // number 값 = 10
out 키워드는 ref와 유사하게 동작하지만, out 키워드를 사용한 매개변수는 메서드 안에서 반드시 값을 할당해야 함.
bool TryDivide(int dividend, int divisor, out double result) { if (divisor != 0) { result = (double)dividend / divisor; return true; } else { result = 0; return false; } } double quotient; bool success = TryDivide(10, 2, out quotient); // success는 true, quotient는 5.0.
구조체 vs 클래스
데이터와 그 데이터를 처리하는 메서드를 묶는 데 사용되는 객체지향 프로그래밍의 개념.
구조체는 값 타입(Value Type), 변수나 배열과 같은 값 자체를 저장하며, 복사할 때 데이터 자체가 복사.
클래스는 참조 타입(Reference Type), 객체에 대한 참조를 저장하며, 변수들은 실제 데이터를 가리키는 포인터 역할.
구조체는 상속을 받을 수 없지만 클래스는 단일 상속 및 다중 상속이 가능.
구조체는 작은 데이터 구조를 나타내거나 간단한 데이터의 그룹을 다룰 때 사용하며, 클래스는 더 복잡한 데이터 구조와 동작을 가지는 객체를 다룰 때 주로 사용.
필드와 메서드
필드와 메서드 예제
class Player { // 필드 private string name; private int level; // 메서드 public void Attack() { // 공격 동작 구현 } }
클래스의 인스턴스
Player player = new Player(); // Player 클래스의 인스턴스 생성 player.Attack(); // Attack 메서드 호출
접근 제한자
public: 외부에서 자유롭게 접근이 가능.
private: 같은 클래스 내부에서만 접근 가능.
protected: 같은 클래스 내부와 상속받은 클래스에서만 접근 가능.
생성자와 소멸자
생성자 예제
class Person { private string name; public Person(string n) // Person person = new Person("gildong");등 으로 호출 가능 { name = n; Console.WriteLine("Person 객체 생성됨."); } }
소멸자 예제
class ResourceOwner : IDisposable { // 리소스 해제 작업을 여기에 구현 public void Dispose() { // 리소스 해제 코드 } }
C#의 경우 가비지 컬렉션 시스템(Garbage Collection)이 메모리 관리를 수행하므로, 개발자가 직접적으로 소멸자를 정의하거나 사용할 필요는 없음. 대신, IDisposable 인터페이스를 구현하여 리소스 관리를 처리할 수 있음.
오버라이딩 과 오버로딩
오버라이딩(Overriding)
부모 클래스에서 이미 정의된 메서드를 자식 클래스에서 재정의하는 것.
상속 관계에 있는 클래스 간에 발생하며, 메서드의 이름, 매개변수 및 반환타입이 동일해야 함.
오버라이딩은 다형성을 구현하는 중요한 방법 중 하나.
class Animal //부모 클래스 { public virtual void MakeSound() //MakeSound 메서드 정의 { Console.WriteLine("Animal makes a sound."); } } class Dog : Animal //자식 클래스 { public override void MakeSound() //MakeSound 메서드 재정의 { Console.WriteLine("Dog barks."); } }
오버로딩 (Overloading)
같은 메서드 이름을 가지면서 매개변수의 개수, 타입, 순서가 다른 여러 버전의 메서드를 작성하는 것.
메서드 이름을 기반으로 다양한 매개변수 조합을 처리할 수 있음.
class Calculator { public int Add(int a, int b) //int형 Add 메서드 { return a + b; } public double Add(double a, double b) //double형 Add 메서드 { return a + b; } }
out, ref 키워드 주의사항
값의 변경 가능성 : ref 매개변수를 사용하면 메서드 내에서 해당 변수의 값을 직접 변경하여 예기치 않은 동작을 초래할 수 있음.
성능 이슈 : 너무 많은 매개변수를 ref로 전달하면 코드의 가독성이 떨어지고 유지보수가 어려워질 수 있음.
변수 변경 여부 주의 : 메서드 내에서 반드시 값을 할당해야 하므로 out 매개변수를 전달할 때 해당 변수의 이전 값이 유지되지 않으므로 주의해야 함.
주간회고 WIL작성
3주차 과제 블랙잭 분석
개인 과제 수행
안드로이드 스튜디오 프로젝트 진행(졸업작품)