추상화와 구현의 분리
추상화와 구현의 분리는 소프트웨어 설계에서 중요한 원칙으로, 시스템을 더 유연하고 유지보수하기 쉽게 만드는 데 기여합니다. 이 원칙은 객체지향 프로그래밍의 핵심 개념 중 하나로, 특히 모듈화 설계에서 다양한 객체가 서로 독립적으로 동작하면서도 협력할 수 있는 기반을 제공합니다.
추상화와 구현
추상화란?
추상화Abstraction는 구체적인 세부 사항을 감추고, 시스템에서 중요한 개념만을 드러내는 과정을 의미합니다.
구현이란?
구현Implementation은 추상화된 개념을 실제 코드로 구현하는 과정입니다. 즉, 추상화된 인터페이스나 추상 클래스가 정의한 행동메서드을 실제로 어떻게 수행할지 구체적인 코드를 작성하는 것입니다. 구현은 객체가 실제로 어떤 방식으로 동작하는지 정의하며, 각 객체는 다른 방식으로 동일한 추상화된 행동을 구현할 수 있습니다.
추상화와 구현의 분리
추상화와 구현의 분리는 인터페이스나 추상 클래스를 통해 시스템의 주요 기능을 정의하고, 구체적인 동작 방식은 나중에 구현되는 방식입니다. 이를 통해 시스템의 기능 변경이나 확장에 유연하게 대응할 수 있으며, 모듈 간의 결합도를 낮춰 유지보수성과 확장성을 높일 수 있습니다.
실무에서의 추상화와 구현의 분리
예시: 도서관 관리 시스템
public interface IBorrowable
{
void Borrow();
void Return();
bool IsBorrowed { get; }
}
public class Book : IBorrowable
{
public string Title { get; private set; }
public bool IsBorrowed { get; private set; }
public Book(string title)
{
Title = title;
IsBorrowed = false;
}
public void Borrow()
{
if (IsBorrowed)
{
throw new InvalidOperationException("Book is already borrowed.");
}
IsBorrowed = true;
}
public void Return() => IsBorrowed = false;
}
public class User : IBorrowable
{
public string Name { get; private set; }
public bool IsBorrowed { get; private set; }
public User(string name)
{
Name = name;
IsBorrowed = false;
}
public void Borrow() => IsBorrowed = true;
public void Return() => IsBorrowed = false;
}
public class LibraryService
{
public void ProcessBorrowing(IBorrowable item)
{
if (!item.IsBorrowed)
{
item.Borrow();
}
else
{
throw new InvalidOperationException("Item is already borrowed.");
}
}
}
- 추상화:
IBorrowable
인터페이스는Borrow()
,Return()
,IsBorrowed
속성을 정의하여 대출 가능한 객체의 행동을 추상화했습니다. - 구현:
Book
과User
클래스는IBorrowable
인터페이스를 구현하여 각각의 대출/반납 로직을 구체적으로 정의합니다. - 분리의 장점:
LibraryService
는IBorrowable
을 구현한 객체라면 어떤 것이든 대출/반납 로직을 처리할 수 있으므로, 시스템은 유연하게 확장될 수 있습니다. 새로운 대출 가능한 개체를 추가하더라도IBorrowable
만 구현하면 됩니다.
추상화와 구현 분리의 장점
유연성: 새로운 기능을 추가하거나 변경할 때 추상화된 인터페이스나 추상 클래스는 그대로 유지하고, 구체적인 구현만 변경하거나 추가할 수 있습니다.
결합도 감소: 구체적인 구현에 의존하지 않고, 추상화된 계약에만 의존하므로, 모듈 간의 결합도를 낮출 수 있습니다. 이는 유지보수성의 향상으로 이어집니다.
확장성: 추상화를 통해 시스템의 기능을 쉽게 확장할 수 있습니다. 새로운 클래스가 추가되더라도 기존 코드를 수정하지 않고도 새로운 객체를 사용할 수 있습니다.
재사용성: 동일한 추상화된 인터페이스나 추상 클래스를 여러 곳에서 재사용할 수 있으므로, 코드 중복을 최소화하고 유지보수성을 높일 수 있습니다.
추상화와 구현의 분리 vs 상속
추상화와 구현의 분리는 상속을 통한 설계와 비교되기도 합니다. 상속은 부모 클래스의 구현을 자식 클래스에 물려주는 방식으로 재사용성을 높이는 방법입니다. 그러나 상속은 상위 클래스와 하위 클래스 간의 강한 결합을 초래할 수 있기 때문에, 구체적인 구현을 포함하지 않는 추상 클래스나 인터페이스를 사용하여 추상화와 구현을 분리하는 것이 더 유연하고 효과적일 수 있습니다.
맺음말
추상화와 구현의 분리는 시스템 설계에서 중요한 원칙으로, 모듈 간의 결합도를 낮추고 시스템의 확장성을 높이는 데 중요한 역할을 합니다. 실무에서는 인터페이스나 추상 클래스를 사용하여 각 객체의 행동을 추상화하고, 구체적인 동작은 나중에 구현할 수 있도록 설계함으로써, 변화하는 요구사항에 유연하게 대응할 수 있습니다.