Menu
Coddy logo textTech

상속보다 합성(Composition)

Coddy C# 여정의 객체 지향 프로그래밍 섹션에 포함된 레슨. 70개 중 41번째.

상속은 클래스 간에 강한 결합을 만듭니다. CarVehicle을 상속하면 Vehicle의 어떤 변경이든 Car를 손상시킬 수 있습니다. 컴포지션은 더 유연한 대안을 제공합니다. 동작을 상속하는 대신 클래스가 해당 동작을 제공하는 객체를 포함합니다.

이동하고 공격할 수 있는 게임 캐릭터를 생각해 보세요. 상속을 사용하면 복잡한 계층 구조를 만들 수 있습니다. 컴포지션을 사용하면 캐릭터에게 필요한 구성 요소를 간단히 제공하면 됩니다.

public class MovementBehavior
{
    public void Move() => Console.WriteLine("Moving...");
}

public class AttackBehavior
{
    public void Attack() => Console.WriteLine("Attacking!");
}

public class Character
{
    private MovementBehavior movement = new MovementBehavior();
    private AttackBehavior attack = new AttackBehavior();
    
    public void Move() => movement.Move();
    public void Attack() => attack.Attack();
}

핵심적인 차이는 관계입니다. 상속은 "is-a"(Dog는 Animal입니다)를 나타내는 반면, 합성은 "has-a"(Character는 movement behavior를 가집니다)를 나타냅니다. 합성을 사용하면 런타임에 behavior를 교체하고, 기능을 자유롭게 결합하며, 취약한 기반 클래스 문제를 피할 수 있습니다.

진정한 계층 관계가 있을 때 상속을 사용하세요. 유연성이 필요하거나, 서로 관련 없는 클래스 간에 동작을 공유할 수 있거나, 동작을 동적으로 변경하려는 경우에는 컴포지션을 선택하세요.

challenge icon

챌린지

쉬움

상속보다 조합의 강력함을 보여 주는 알림 시스템을 만들어 보겠습니다. 복잡한 알림 클래스 계층 구조를 만드는 대신, 교체 가능한 behavior 구성 요소를 제공하여 NotificationSender를 조합합니다.

코드를 세 개의 파일로 구성합니다:

  • Behaviors.cs: Notifications namespace에서 알림 전송의 서로 다른 측면을 처리하는 두 개의 behavior 클래스를 Create합니다:
    • FormattingBehavior - Format(string message) method를 가지며, 시작 부분에 [ALERT] 를 추가하고 끝부분에 [END]를 추가하여 message를 반환합니다
    • DeliveryBehavior - Deliver(string channel, string message) method를 가지며, Sending via {channel}: {message} 형식의 문자열을 반환합니다
  • NotificationSender.cs: Notifications namespace에서 조합을 사용해 behavior를 결합하는 NotificationSender class를 Create합니다. sender는 다음을 수행해야 합니다:
    • FormattingBehaviorDeliveryBehavior의 인스턴스를 모두 private fields로 포함합니다
    • delivery channel 이름을 저장하는 Channel property (string)를 가집니다
    • channel 이름을 accepts하는 constructor를 가집니다
    • 먼저 formatting behavior를 사용해 message를 formatting한 다음 delivery behavior를 사용해 전달하고 최종 결과를 반환하는 Send(string message) method를 가집니다
  • Program.cs: main 파일에서 input으로부터 channel을 사용해 NotificationSender를 Create한 다음, input으로부터 message를 전송합니다. 조합된 behavior가 함께 작동하는 방식을 보여 주도록 결과를 출력합니다.

두 개의 input을 받습니다:

  • delivery channel 이름(예: Email, SMS)
  • 전송할 message

notification sender에서 Send()를 호출한 결과를 출력합니다.

예를 들어 input이 EmailServer is down이라면 출력은 다음과 같아야 합니다:

Sending via Email: [ALERT] Server is down [END]

NotificationSender가 어떤 것도 상속하지 않고 단순히 formatting 및 delivery behavior를 "has"한다는 점에 주목하세요. 이 조합 접근 방식을 사용하면 sender class를 변경하지 않고도 두 behavior 중 하나를 쉽게 교체하거나, 완전히 다른 class에서 이러한 behavior를 재사용할 수 있습니다!

직접 해보기

using System;
using Notifications;

class Program
{
    public static void Main(string[] args)
    {
        // 입력 읽기
        string channel = Console.ReadLine();
        string message = Console.ReadLine();

        // TODO: 채널로 NotificationSender 생성
        
        // TODO: 메시지를 보내고 결과 출력
        
    }
}
quiz icon실력 점검

이 레슨에는 짧은 퀴즈가 포함되어 있습니다. 레슨을 시작해 문제를 풀고 진행 상황을 기록하세요.

객체 지향 프로그래밍의 모든 레슨

직접 연습해 보세요: 온라인 C# 컴파일러