DEV Community

ulalax
ulalax

Posted on

"Tell,Dont ask" 원칙

'Tell, Don't Ask' 원칙: 객체지향 프로그래밍의 핵심

소개

'Tell, Don't Ask'는 객체지향 프로그래밍(OOP)에서 중요한 설계 원칙입니다. 이 원칙은 외부 객체가 다른 객체의 상태를 직접 조회하지 않고, 필요한 행동을 요청하는 방식으로 코드를 작성해야 한다고 강조합니다. 이를 통해 객체의 내부 상태가 캡슐화되어 외부에 노출되지 않으며, 객체 간의 결합도가 낮아져 유지보수성과 재사용성이 향상됩니다.

게임 개발 예제

이 원칙을 더 잘 이해하기 위해, 게임 개발의 맥락에서 예제를 살펴보겠습니다.

잘못된 접근 (원칙 위반)

이 예제에서는 Player 클래스가 Weapon 객체의 상태(특히 탄약 수)를 확인한 후, 공격 여부를 결정합니다.

public class Weapon
{
    public int Ammo { get; private set; }

    public Weapon(int initialAmmo)
    {
        Ammo = initialAmmo;
    }

    public void Fire()
    {
        Ammo--;
        Console.WriteLine("Weapon fired! Remaining ammo: " + Ammo);
    }
}

public class Player
{
    public void Attack(Weapon weapon)
    {
        if (weapon.Ammo > 0)
        {
            weapon.Fire();
        }
        else
        {
            Console.WriteLine("Cannot attack: No ammo left!");
        }
    }
}
Enter fullscreen mode Exit fullscreen mode

여기서 Player 클래스는 Weapon 객체의 Ammo 상태를 조회한 뒤, 그 상태에 따라 행동을 결정합니다. 이 방법은 Player 클래스가 Weapon 클래스의 내부 상태에 의존하게 하여, 두 클래스 간의 결합도를 높이고 Weapon 클래스의 캡슐화를 깨뜨리게 됩니다.

올바른 접근 (원칙 준수)

이제 'Tell, Don't Ask' 원칙을 준수하는 방법을 살펴보겠습니다. 이번 예제에서는 Player 클래스가 무기의 상태를 묻지 않고, 단순히 공격을 요청합니다.

public class Weapon
{
    private int _ammo;

    public Weapon(int initialAmmo)
    {
        _ammo = initialAmmo;
    }

    public void Fire()
    {
        if (_ammo > 0)
        {
            _ammo--;
            Console.WriteLine("Weapon fired! Remaining ammo: " + _ammo);
        }
        else
        {
            Console.WriteLine("No ammo left!");
        }
    }
}

public class Player
{
    public void Attack(Weapon weapon)
    {
        weapon.Fire(); // 상태를 묻지 않고 바로 행동을 요청
    }
}
Enter fullscreen mode Exit fullscreen mode

이 올바른 접근법에서는 Player 클래스가 Weapon 객체의 상태를 전혀 알 필요가 없습니다. Weapon 클래스는 자신의 상태를 내부에서 관리하며, 외부에 노출하지 않고 적절한 행동을 결정합니다. 이를 통해 객체 간의 결합도가 줄어들고, Weapon 클래스의 캡슐화가 유지됩니다.

개념 설명

  1. 캡슐화 강화: Weapon 클래스는 자신의 상태를 외부에 노출하지 않고 스스로 관리합니다. 외부 객체는 단순히 행동을 요청하기만 하면 되며, 이는 캡슐화를 유지하는 데 중요한 역할을 합니다.

  2. 결합도 감소: Player 클래스는 더 이상 Weapon 클래스의 내부 상태에 의존하지 않습니다. 이로 인해 두 클래스 간의 결합도가 낮아지고, 각 클래스가 변경되더라도 서로에게 미치는 영향이 줄어듭니다.

  3. 유지보수성 향상: Weapon 클래스의 내부 로직이 변경되더라도 Player 클래스는 영향을 받지 않습니다. 이는 코드의 유지보수를 더 쉽게 만들고, 시스템의 복잡성을 줄이는 데 기여합니다.

  4. 코드 단순화: 상태를 확인한 뒤 행동을 결정하는 복잡한 코드 대신, 단순히 행동을 요청하는 코드로 전환하여 가독성과 단순성을 높입니다.

Martin Fowler의 견해

'Tell, Don't Ask' 원칙은 많은 상황에서 유용하지만, 모든 경우에 무조건 적용해야 하는 것은 아닙니다. Martin Fowler는 그의 블로그 포스트 "Tell, Don't Ask"에서 이 원칙의 중요성을 설명하면서도, 이를 지나치게 엄격하게 적용하는 것에 대해 주의해야 한다고 강조합니다.

Fowler는 객체지향 설계에서 이 원칙을 따르면서도 코드의 명확성과 가독성을 유지하는 것이 중요하다고 말합니다. 때로는 객체의 상태를 직접 확인하고 그에 따라 행동을 결정하는 것이 더 명확하고 이해하기 쉬울 수 있습니다. 예를 들어, 지나치게 복잡한 로직을 객체 내부에 숨기기보다는, 외부에서 간단하게 상태를 확인하고 적절한 결정을 내리는 것이 더 나을 때도 있습니다.

따라서, 'Tell, Don't Ask' 원칙을 적용할 때는 상황에 맞게 유연하게 접근하는 것이 중요합니다. 객체의 캡슐화와 결합도를 고려하면서도, 코드의 가독성과 유지보수성을 항상 염두에 두어야 합니다.

요약

'Tell, Don't Ask' 원칙은 객체 간의 상호작용을 단순화하고, 코드의 유지보수성을 높이는 중요한 개발 팁입니다. 게임 개발에서 이 원칙을 준수하면, 캐릭터와 무기와 같은 객체 간의 상호작용을 더 유연하고 효율적으로 처리할 수 있습니다. 이를 통해 더 나은 소프트웨어 설계와 코드 품질을 유지할 수 있습니다.

Top comments (0)