Search

추상 클래스

class
구조
상태
완료
날짜
목차

추상클래스에 대한 개인적인 생각

인터페이스에 대해 앞서 설명했듯이, 제 생각에는 인터페이스와 추상 클래스는 주로 유지 보수를 위한 구조라고 생각합니다.
추상 클래스와 인터페이스가 유지 보수를 원활하게 하는 이유를 이해한다면, 추상 클래스를 사용하는데 큰 문제가 없을 것입니다.

추상 클래스

상속을 위한 설계 : 추상 클래스는 상속을 전제로 설계됩니다. 공통의 기능이나 인터페이스를 제공하면서, 구체적인 구현은 상속받는 하위 클래스에서 수행하도록 합니다.
이 부분 자체가 유지 보수를 위해 존재한다고 생각됩니다.
추상 메서드 : 추상 클래스는 하나 이상의 추상 메서드를 포함할 수 있습니다. 이러한 메서드는 상속받는 클래스에서 반드시 구현해야 합니다.
인스턴스화 불가 : 직접적으로 인스턴스를 생성할 수 없으며, 상속을 통해 확장된 하위 클래스를 통해서만 사용됩니다.

추상클래스의 기본 구조

추상 클래스는 다양한 공통적인 특성과 행동을 정의하는 데 사용됩니다.
예를 들어, 게임 내 다양한 적타입이 있다고 가정해 봅시다.
이 적들은 모두 공격, 이동, 사망 등의 공통된 행동을 가지고 있지만, 각각의 구체적인 행동 방식은 다를 수 있습니다.
public abstract class Enemy { public float health; // 모든 적은 공격 방식을 가지고 있지만, 구체적인 공격 로직은 다를 수 있습니다. public abstract void Attack(); // 이동 로직은 대부분의 적에게 공통적일 수 있으므로, 구현을 제공할 수 있습니다. public virtual void Move() { Console.WriteLine("Enemy moves"); } // 사망 로직은 구현을 포함할 수 있으며, 필요에 따라 하위 클래스에서 오버라이드될 수 있습니다. public virtual void Die() { Console.WriteLine("Enemy dies"); } } public class Zombie : Enemy { // Attack 메서드를 구체적으로 구현합니다. public override void Attack() { Console.WriteLine("Zombie attacks"); } // 필요하다면 Move 메서드를 오버라이드할 수 있습니다. public override void Move() { Console.WriteLine("Zombie shuffles forward"); } } // 다른 적들 구현 ~~~
C#
복사

추상클래스를 사용하는 이유

기본 클래스 대신 추상 클래스를 사용하는 명확한 이유는 조금 복잡할 수 있지만, 그 이유는 추상화의 명확성과 메서드 구현의 강제성 때문이라고 생각합니다.
추상화 명확성 : 추상 클래스는 개발자에게 "이 클래스는 상속을 위해 설계되었으며, 직접 인스턴스화될 수 없다"는 명확한 메시지를 전달합니다.
강제된 메서드 구현 : 추상 클래스를 사용하면 하위 클래스가 특정 메서드를 반드시 구현하도록 강제할 수 있습니다. 이는 모든 하위 클래스가 일관된 인터페이스와 행동을 가지도록 보장하는데 유용합니다.

추상클래스의 기본적인 장점

재사용성 : 공통된 기능을 추상 클래스에서 정의하고, 이를 여러 하위 클래스에서 재사용할 수 있습니다.
확장성 : 새로운 적 타입을 추가하려면 추상 클래스를 상속받아 필요한 메서드를 구현하기만 하면 됩니다. 이는 게임의 확장성을 크게 향상시킵니다.
유연성 : 공통적인 로직을 추상 클래스에서 제공하면서도, 특정 행동의 구체적인 구현은 하위 클래스에서 정의할 수 있어 유연한 설계가 가능합니다.
유지보수 : 공통 로직이 한 곳에 집중되어 있어, 수정이 필요할 경우 여러 곳을 변경하지 않고도 추상 클래스에서만 수정하면 됩니다.

추상클래스의 다형성

인터페이스의 이점과 마찬가지로 추상 클래스 또한 다형성을 통해 서로 다른 클래스의 인스턴스를 하나의 공통 추상 클래스 타입으로 관리할 수 있다는 것입니다.
public abstract class Enemy { public abstract void Update(); } public class Zombie : Enemy { public override void Update() { Console.WriteLine("Zombie Update"); } } public class Vampire : Enemy { public override void Update() { Console.WriteLine("Vampire Update"); } } // 게임 루프에서 적들을 관리하는 예 public class Game { private List<Enemy> enemies = new List<Enemy>(); public Game() { enemies.Add(new Zombie()); enemies.Add(new Vampire()); // 여기에 더 많은 적 타입을 추가할 수 있습니다. } public void UpdateGame() { foreach (var enemy in enemies) { enemy.Update(); } } }
C#
복사

추상클래스와 인터페이스의 동시 활용

추상 클래스를 활용하여 공통 인터페이스와 재사용 가능한 구현을 제공하는 방법은 매우 유용합니다.
// 공통 인터페이스를 정의합니다. public interface IMovable { void Move(); } // 추상 클래스로 캐릭터의 공통 구현과 인터페이스 구현을 함께 제공합니다. public abstract class Character : IMovable { protected float health; public Character(float initialHealth) { health = initialHealth; } public void Move() { Console.WriteLine("Character moves."); } // 공통적으로 재사용할 수 있는 피해 받기 메소드 public virtual void TakeDamage(float damage) { health -= damage; Console.WriteLine($"Character took {damage} damage, remaining health: {health}"); } // 공통적인 회복 메커니즘을 제공합니다. public void Heal(float amount) { health += amount; Console.WriteLine($"Character healed {amount}, total health: {health}"); } } // 'Player' 클래스는 'Character' 추상 클래스를 상속받아 구현됩니다. // 이 뿐만 아니라, Character 이외의 다른 인터페이스를 상속 받아서 같이 구현할 수 있습니다. public class Player : Character { public Player(float initialHealth) : base(initialHealth) {} // 'IMovable' 인터페이스 구현 public void Move() { Console.WriteLine("Player moves with arrow keys."); } // 필요에 따라 'TakeDamage'를 오버라이드 할 수 있습니다. public override void TakeDamage(float damage) { // 플레이어 특유의 데미지 감소 로직 base.TakeDamage(damage / 2); // 데미지를 반으로 줄입니다. } } // 'Enemy' 클래스 역시 'Character'를 상속받아 다른 구현을 제공합니다. public class Enemy : Character { public Enemy(float initialHealth) : base(initialHealth) {} // 'IMovable' 인터페이스 구현 public void Move() { Console.WriteLine("Enemy moves towards the player."); } }
C#
복사