인터페이스(Interface)란?
인터페이스는 해당 인터페이스를 상속받는 모든 클래스가 반드시 따라야 하는 문법적 계약(syntactical contract)입니다. 인터페이스 자체는 계약의 '무엇을(what)' 수행해야 하는지를 정의하고, 실제 구현 방식 즉 '어떻게(how)' 수행할지는 인터페이스를 구현하는 파생 클래스가 결정합니다.
C#에서는 관례적으로 인터페이스 이름 앞에 대문자 I를 붙여 명명합니다(예: ITransactions). 인터페이스에는 메서드, 속성, 이벤트 등의 시그니처만 선언할 수 있으며, 구현 세부 사항은 이를 상속받는 클래스가 작성해야 합니다.
예제 코드
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System;
namespace InterfaceApplication {
public interface ITransactions {
// 인터페이스 멤버
void showTransaction();
double getAmount();
}
public class Transaction : ITransactions {
private string tCode;
private string date;
private double amount;
public Transaction() {
tCode = " ";
date = " ";
amount = 0.0;
}
public Transaction(string c, string d, double a) {
tCode = c;
date = d;
amount = a;
}
public double getAmount() {
return amount;
}
public void showTransaction() {
Console.WriteLine("Transaction: {0}", tCode);
Console.WriteLine("Date: {0}", date);
Console.WriteLine("Amount: {0}", getAmount());
}
}
class Tester {
static void Main(string[] args) {
Transaction t1 = new Transaction("001", "8/10/2012", 78900.00);
Transaction t2 = new Transaction("002", "9/10/2012", 451900.00);
t1.showTransaction();
t2.showTransaction();
Console.ReadKey();
}
}
}실행 결과
Transaction: 001 Date: 8/10/2012 Amount: 78900 Transaction: 002 Date: 9/10/2012 Amount: 451900
위 예제에서 Transaction 클래스는 ITransactions 인터페이스를 구현하며, 인터페이스에 선언된 showTransaction()과 getAmount() 메서드를 반드시 정의해야 합니다. 이처럼 인터페이스를 사용하면 여러 클래스가 동일한 계약을 따르도록 강제할 수 있어 코드의 일관성과 유지보수성이 크게 향상됩니다.
상속(Inheritance)이란?
상속은 하나의 클래스를 다른 클래스를 기반으로 정의할 수 있게 해주는 객체 지향 프로그래밍의 핵심 개념입니다. 상속을 활용하면 애플리케이션의 생성과 유지보수가 훨씬 쉬워지고, 기존 코드의 기능을 그대로 재사용할 수 있어 개발 시간도 크게 단축됩니다.
상속의 핵심 아이디어는 IS-A 관계를 구현하는 것입니다. 예를 들어, 포유류는 동물이다(mammal IS-A animal), 개는 포유류이다(dog IS-A mammal)라는 관계가 성립하면, 개 역시 동물이라는 결론이 자연스럽게 도출됩니다.
C#에서는 콜론(:) 기호를 사용하여 클래스 간의 상속 관계를 표현합니다. 파생 클래스는 기반 클래스의 public 및 protected 멤버를 물려받아 사용할 수 있습니다.
예제 코드
using System;
namespace InheritanceApplication {
class Shape {
public void setWidth(int w) {
width = w;
}
public void setHeight(int h) {
height = h;
}
protected int width;
protected int height;
}
// 파생 클래스
class Rectangle : Shape {
public int getArea() {
return (width * height);
}
}
class RectangleTester {
static void Main(string[] args) {
Rectangle Rect = new Rectangle();
Rect.setWidth(5);
Rect.setHeight(7);
// 객체의 면적 출력
Console.WriteLine("Total area: {0}", Rect.getArea());
Console.ReadKey();
}
}
}실행 결과
Total area: 35
위 예제에서 Rectangle 클래스는 Shape 클래스를 상속받습니다. width와 height 필드는 protected로 선언되어 있기 때문에 파생 클래스인 Rectangle 내부에서 직접 접근할 수 있습니다. 결과적으로 Rectangle은 별도의 너비·높이 설정 로직 없이도 기반 클래스의 기능을 재사용하면서 자신만의 getArea() 메서드를 추가로 확장한 것입니다.