[HCI] 6주차 인터페이스

정수현·2025년 4월 14일

C#

목록 보기
7/10

인터페이스 (Interface)

다중 상속

  • 하나의 클래스가 여러 개의 클래스로부터 상속 받는 것
  • C#에서는 하나의 클래스가 동시에 두 개 이상의 클래스에서 상속 받을 수 없다.
    = 두 개 이상의 부모 클래스를 가질 수 없다.
    → 인터페이스를 통해 다중 상속할 수 있다.

📍 인터페이스

  • 행동적인 특성만을 정의 (메서드, 속성, 인덱서, 이벤트)
  • 자식 클래스에 구현되어야 하는 기능을 선언할 시, 일반적으로 이질적인 클래스들이 공통으로 제공해야 할 메소드들을 선언할 때 사용한다.
  • 다중 상속을 구현하기 위해 사용한다.
  • class 키워드 대신 interface 키워드를 사용하여 선언한다.
interface IPrintable
{
    void Print();
}

class Document : IPrintable
{
    public void Print() { Console.WriteLine("Print document"); }
}

class Photo : IPrintable
{
    public void Print() { Console.WriteLine("Print photo"); }
}
  • 여기서 Document 클래스와 Photo 클래스가 서로 이질적인 관계이다.

📍 클래스 & 인터페이스 관계

  • class & class ⇒ 상속 관계
  • class & interface ⇒ 구현 관계
  • interface & interface ⇒ 상속 관계

🍀 클래스 & 인터페이스 사용 예시 1

interface IMyInterface: IBase1, IBase2
{
	void MethodA();
    void MethodB();
}
  • 여러 개의 인터페이스를 상속 받은 인터페이스는 상위 인터페이스의 메서드를 모두 구현해야 한다.
class ClassA: IFace1, IFace2
{
	// class members, implementing interface
} 

class ClassB: BaseClass, IFace1, IFace2
{
	// class members, implementing interface
}
  • ClassB : 클래스와 인터페이스를 함께 상속 받는 경우, 기본 클래스가 처음에 위치한다.
    BaseClass ⇒ 클래스
    IFace1 & IFace2 ⇒ 인터페이스

🍀 클래스 & 인터페이스 사용 예시 2

interface IScalable 
{ 
	void ScaleX(float factor); 
    void ScaleY(float factor); 
} 

public abstract class DrawObject 
{ 
	public DrawObject() {} 
    public abstract void Print(); 
} 

public class TextObject: DrawObject, IScalable 
{ 
	private string text; 
    
	public TextObject(string text) 
	{ 
    	this.text = text; 
    }
    
	public void ScaleX(float factor) 
	{ 
		Console.WriteLine("ScaleX: {0} {1}", text, factor); 
	} 
        
    public void ScaleY(float factor) 
    { 
    	Console.WriteLine("ScaleY: {0} {1}", text, factor); 
    } 
        
	public override void Print() 
	{ 
		Console.WriteLine(“TextObject: {0}", text); 
	} 
}
  • 클래스와 인터페이스를 동시에 상속 받을 땐 클래스가 더 앞에 온다.
  • 추상 클래스(부모)는 abstract 메서드로 선언되고, 반드시 자식 클래스에서 override 메서드로 구현한다.
  • 인터페이스는 키워드 없이 반드시 자식에서 구현해야 한다.

📍 IComparable 인터페이스

  • 객체 간 비교를 가능하게 해주는 인터페이스
  • 정렬을 하기 위해 사용된다.
  • ComparableTo 메서드를 제공한다.

int CompareTo (Object obj)

  • obj 인수 : 인터페이스를 구현하는 클래스와 같은 형식
  • 리턴 값은 현 객체가 obj보다 작으면 → 음수 / 같은면 → 0 / obj보다 크면 → 양수를 리턴한다.
public clas Age: IComparable
{

	protected int m_value;
    
    public Age(int value)
    {
    	m_value = value;
    }

	public int CompareTo(object obj)
    {
    	// 실제 int 비교
    	if(obj is Age temp)
        	return m_value.CompareTo(temp.m_value);
        
        throw new ArgumentException("Object is not Age");
    }
}

🍀 Sort() 활용 예시

List<Age> list = new List<Age>
{
	new Age(25), new Age(20), new Age(30)
};

list.Sort(); 
  • list.Sort() : CompareTo 에 따라 정렬
  • List<T>.Sort() 메서드는 내부에서 CompareTo()를 호출하여 정렬한다.

📍 IEquatable 인터페이스

  • 객체가 다른 객체와 같은지 비교할 수 있도록 해주는 인터페이스

bool Equals (Object obj)

  • obj 인수 : 인터페이스를 구현하는 클래스와 같은 형식
  • 리턴값 == objtrue 를 리턴
    리턴값 != objfalse 를 리턴

🍀 IEquatable 인터페이스 예시

Person 클래스가 같은 사람인지 비교

public class Person: IEquatable<Person>
{
	public string name;
    public int age;
    
	public bool Equals (Person p)
    {
    	if(p is Person)
        	return name.Equals(p.name && age.Equals(p.age);
            
        throw new ArgumentException("Object is not Person");
    }
}

사용 예시

Person p1 = new Person { name = "Suhyeon", age = 22 };
Person p2 = new Person { nae = "Suhyeon", age = 22 } ;

Conole.WriteLine(p1.Equals(p2)); // -> true

📍 IEnumerable 인터페이스

  • 컬렉션을 반복할 수 있도록 해주는 인터페이스
  • 반복을 위한 "열거자(IEnumerator)"를 반환한다.
  • IEnumerator GetEnumerator()
    foreach 루프가 동작하려면 이 메서드를 사용해야 한다.

🍀 IEnumerable foreach문 예시

foreach -> IEnumerable.GetEnumerator() -> IEnumerator 사용 (MoveNext + Current)

📍 IEnumerator 인터페이스

  • 반복하면서 현재 위치를 추적할 수 있도록 해주는 인터페이스
  • 아래와 같은 메서드로 구성되어 있다.
    object Current : 컬렉션의 현재 요소를 가져오는 속성
    bool MoveNext() : 컬렉션의 다음 요소로 이동하는 메서드
    void Reset() : 컬렉션의 첫번째 요소 앞의 초기 위치로 설정하는 메서드

🍀 IEnumerable interface 예시

public class Tokens: IEumerable
{
	private string[] elements;
    
    public Tokens(string source, char[] delimiters)
    {
    	elements = source.Split(delimiters);
    }
    
    // implementaion of GetEnumerator()
    public IEnumerator GetEnumerator()
    {
    	return new TokenEnumerator(this);
    }
    
    // implementation of TokenEnumerator
    private class TokenEnumerator 
    private class TokenEnumerator: IEnumerator
    {
    	private int positioin = -1;
        private Tokens t;
        public TokenEnumerator(Tokens t)
        {
        	this.t = t;
        }
        
        public void Reset()
        {
        	position = -1;
        }
        
        public bool MoveNext()
        {
        	if(position < t.elements.Length-1)
            {
            	position+++;
                return true;
            }
            else
            	return false;
        }
        
        public object Current
        {
        	get { return t.elements[position] };
        }        
    }
}

Token 테스트

class EnumeratorTest
{
	pubilc static void Main()
    {
    	Tokens f = new Tokens("This is a sample test.", new char[] {' ', '-'});
        foreach (string item in f)
        {
        	Console.WriteLine(item);
        }
    }
}

💡 추상 클래스와 인터페이스의 공통점과 차이점

  • 모두 추상의 의미이다.
  • new 키워드를 사용하여 객체를 생성하는 것이 불가능하다.
  • 자식 클래스에서 모든 메서드를 구현하였을 경우에만 기능을 발휘할 수 있다.
  • 클래스와 메서드가 abstract로 선언되어 있다면 인터페이스로 변환할 수 있다.

🍀 추상 클래스 → 인터페이스 변환 예시

추상 클래스

abstract public class StarPlayer
{
	public abstract void GoodPlay();
    public abstract void Handsome();
}

인터페이스

interface IStarPlayer
{
	void GoodPlay();
    void Handsome();
}
  • 모든 추상 클래스가 인터페이스로 변환될 수 없다.
  • 추상 메서드는 override 키워드를 사용한다.
  • 추상 클래스는 다중 상속을 지원하지 않는다.

📍 is 연산자

  • 데이터의 형 변환이 가능하면 true를 반환한다.
  • 실패 시 결과 : false
  • 사용 용도 : 타입의 확인을 위해 사용한다. (확인 후 수동 변환)
Bird b;
if (a is Bird)
	b = (Bird)a; // 안전한 형 변환
else
	Console.WriteLine("Not a Bird.);

📍 as 연산자

  • 객체 사이의 형 변환 연산자
  • 오류 발생 시, exception 발생 없이 null을 반환한다.
  • 실패 시 결과 : null
  • 사용 용도 : 타입을 바꾸고 싶을 때 사용한다. (안전하게 형 변환)
Bird b = a as Bird; // 형 변환
if (b == null)
	Console.WriteLine("Not a Bird.")

📍 Boxing

  • 값형식 → 참조형식으로 바꾸는 것
  • 암시적 변환
int a = 127;
object o1 = a;
object o2 = o1;

📍 UnBoxing

  • 참조형식 → 값형식으로 바꾸는 것
  • 명시적 변환
  • int b = (int)o2;

📍 메서드 오버로딩

  • 한 클래스 내에서 두 개 이상의 이름이 같은 메서드를 작성한다.
    ✔ 메서드 이름이 동일해야 한다.
    ✔ 매개 변수의 개수가 서로 다르거나, 타입이 서로 달라야 한다.
    ✔ 리턴 타입은 오버로딩과 관련 없다.
class Method overloading

📍 메서드 오버라이딩

  • 부모 클래스의 메서드를 자식 클래스에서 재정의한다.
  • 동적 바인딩이 발생한다.
    ✔ 자식 클래스에서 오버라이딩된 메서드가 무조건 실행되도록 동적 바인딩 된다.

0개의 댓글