abstract include interface(2)
interface Fightable extends Movable,Attackable{} //extends 인터페이스에서 참조하는 다른 인터페이스
//단 , class에서 상속받을 때는 implements
interface Movable {void move(int x, int y);}
interface Attackable {void attack(Unit u);}
//위 인터페이스들은 메서드앞에 public abstract가 컴파일 시에 붙게 되었다.
class Unit{
int currentHP; //유닛의 체력
int x; //유닛의 x좌표
int y; //유닛의 y좌표
}
class Fighter extends Unit implements Fightable{
public void move(int x, int y) {/*생략*/}
public void attack(Unit u) {/*생략*/}//오버라이딩 비슷
}
public class interfacetest {
public static void main(String[] args) {
Fighter f = new Fighter();
if (f instanceof Unit) {
System.out.println("f는 Unit 자손임");
}
if (f instanceof Fightable) {
System.out.println("f는 Fightable 인터페이스를 구현함");
}
if (f instanceof Movable) {
System.out.println("f는 Movable 인터페이스를 구현함");
}
if (f instanceof Attackable) {
System.out.println("f는 Attackable 인터페이스를 구현함");
}
}
}
(1)에서 쓰던 인터페이스 마지막 코드인데 여기서 인터페이스 Fightable을 클래스 Fighter가 구현했을 때, 다음과 같이 Fighter 인스턴스를 Fightable 타입의 참조변수로 참조하는 것이 가능하다.
Fightable f=new Fighter();
Fightable f=(Fightable) new Fighter();
또 attack(Unit u)에서 인터페이스의 매개변수의 의미는 그 인터페이스를 구현한 클래스의 인스턴스를 반환하라는 의미이기도 하다. 그리고 메서드의 리턴타입으로 인터페이스의 타입을 지정하는 것이 가능하다.
전자
void attack(Fightable f);
ㄴFightable f = new Fighter(); 필
후자
Fightable method(){
...
return new Fighter(); 캔
}
class A{
void autoplay(I i) {
i.play();
}
}
interface I{
public abstract void play();
}
class B implements I{
public void play() {//인터페이스 상속으로인한 구현 클래스
System.out.println("play in B class");
}
}
class C implements I{
public void play() {//인터페이스 상속으로인한 구현 클래스
System.out.println("play in C class");
}
}
public class interfaceparse {
public static void main(String[] args) {
A a=new A();
a.autoplay(new B());//void autoplay 호출
a.autoplay(new C());
}
}
클래스 A가 인터페이스 I를 사용해서 작성이되긴 하였지만 이처럼 매개변수를 통해서 인터페이스I를 구현한 클래스의 객체를 동적으로 제공받아야 한다.
이렇게 매개변수를 통해 동적으로도 제공받을 수 있지만 다음과 같이 제3의 클래스를 통해서 제공받을 수도 있다.
위 코드에서 직접적인 관계에 있는 클래스간의 상호작용에는 만약 C클래스가 추가 되어지면 바뀌어야 하는 값? 매개변수? 들이 너무 많다. 하지만 이처럼 인터페이스로 간접적인 관계를 만들어주면 D, E, F클래스가 추가가 돼도 동적으로 메인부에서 인스턴스를 생성해 인터페이스 메서드를 구현해준 클래스에 한해 대입만 해주면 수정할 부분이 직접적인 관계보다 간접적인 관계에 있어 더 수월하다는 의미이다. 여기서 간접적이라는 것은 B와 C를 인터페이스 분리를 통해 A에 절대적으로 영향을 미치게 할 수 없다는 의미이다.
interface I{
public abstract void methodB();
}
class B implements I{
public void methodB() {
System.out.println("methodB in B class");
}
public String toString() {
return "class B";
}
}
class InstanceManager{
public static I getInstance() {
return new B();//getinstance method return new B() to type"i"
//만약 수정이 생기면 getInstance 메서드를 수정만 하면 된다.
}
}
class A{
void methodA() {
I i=InstanceManager.getInstance();//I i=new B();
i.methodB();//class B가 구현해준 인터페이스 메서드와 반환받은 string 형의 class B 반환
System.out.println(i.toString());//i로 object클래스의 메서드 호출이 가능하다.
}
}
public class interfaceparse {
public static void main(String[] args) {
A a=new A();
a.methodA();
}
}
코드 설명
1. 인터페이스 I선언
2. 인터페이스 I에 기본 설계도 methodB 깡통 선언
3. B클래스 선언과 동시에 인터페이스 I를 상속? 구현하는 클래스라고 선언
4. 인터페이스 I 메서드를 문자열 출력하는 메서드 B를 구현함
5. 인스턴스 매니저라는 클래스를 생성해서 객체를 받아올 수 있는 클래스를 생성함.
6. 클래스 A에서는 I i = 인스턴스매니저 클래스에서. 겟인스턴스라는 메서드로 반환된 new B()
주구장창 길게 썼지만 I i=new B(); 와 같다.
(I i=InstanceManager.getInstance();//I i=new B();)
7.인터페이스 객체가 만들어졌으니 클래스B가 구현해준 메서드를 i.methodB(); 로 불러온다.
마지막 메인메서드에서 A클래스 객체 생성으로 바로 호출 가능하며 수정시나 추가시에 인스턴스매니저 클래스의 리턴 옆 new B만 수정해주면 되므로 이것도 실속있는 선언법이다.
인스턴스 끝.
오늘 고쳐야할 점
반환형 주의하기
무조건 상속 관념 버리기