참조변수의 타입이 메서드를 구현한 클래스의 경우 메서드를 호출하면 어떤 메서드가 호출될지 정적으로 정해진다.
오버로딩으로 매개변수에 따른 여러 메서드가 있다고 해도 같은 원리가 적용된다.
public class StaticTest {
public static void main(String[] arg) {
StaticDspatch staticCase = new StaticDspatch();
staticCase.print();
}
}
public class StaticDspatch{
public void print(){
System.out.println("this is Static Dispatch");
}
public void print(String str) {
System.out.println("this is Static Dispatch (" + str + ")");
}
}
// 예시 1.
public class DynamicDispatchTest {
public static void main(String[] arg) {
Printable dynamicDispatch = new DynamicDispatch();
dynamicDispatch.print();
PrintAbstract dynamicDispatchAbst = new DynamicDispatchAbstractChild();
dynamicDispatchAbst.print();
}
}
public class DynamicDispatchAbstractChild extends PrintAbstract{
@Override
void print() {
System.out.println("this is Dynamic Dispatch abstract PrintAbstract");
}
}
public class DynamicDispatch implements Printable{
public void print(){
System.out.println("this is Dynamic Dispatch");
}
}
public abstract class PrintAbstract {
abstract void print();
}
public interface Printable {
void print();
}
//--------------------------------------------------------------------
// 예시 2.
List <Service> svc = Arrays.asList(new MyService1(), new MyService2());
svc.forEach(s -> s.run());
public class SNSFirst {
/*
문제점 1. 객체의 타입을 판별하는 방식으로 if 문 로직을 사용함 (instanceof 는 안티패턴으로 많이 지적)
1-1. if 문 로직에 걸리지 않을 수도 있으며 if 문 로직을 그대로 통과해버리면 로직에 장애가 발생
1-2. 새로운 SNS 종류가 추가 될 시 새로운 SNS 타입을 반영하는 if 문 로직을 추가해줘야함 : 잊고 빼먹을 여지가 있음
-> 개선 시도
*/
// Post
interface Post {
void postOn(SNS sns);
}
static class Text implements Post {
public void postOn(SNS sns) {
// 문제 지점
if (sns instanceof Facebook) {
System.out.println("text - facebook");
}
if (sns instanceof Twitter) {
System.out.println("text - twitter");
}
// if (sns instanceof GooglePlus) {
// System.out.println("text - google plus");
// }
}
}
static class Picture implements Post {
public void postOn(SNS sns) {
// 문제 지점
if (sns instanceof Facebook) {
System.out.println("picture - facebook");
}
if (sns instanceof Twitter) {
System.out.println("picture - twitter");
}
}
}
// SNS
interface SNS{
}
static class Facebook implements SNS {
};
static class Twitter implements SNS {
};
// static class GooglePlus implements SNS {
// };
// main
public static void main(String[] args) {
List<Post> posts = Arrays.asList(new Text(),new Picture());
List<SNS> sns = Arrays.asList(new Facebook(),new Twitter() // , new GooglePlus()
);
// 다이나믹 디스패치 수행 : 이중 for문
posts.forEach( p -> sns.forEach( s -> p.postOn(s)));
// ==
// posts.forEach((Post p) -> sns.forEach((SNS s) -> p.postOn(s)));
}
}
public class SNSSecond {
// 문제점 1을 개선하여 나온 2번째 코드 : 메서드 오버로딩과 SNS 를 구체화 하여 매개변수로 받아 처리
/*
문제점 2. 적용 불가능
55번째 줄 컴파일 시점에 SNS타입을 찾을수 없다는 내용의 에러 발생
원인 : 메서드 오버로딩 시 매개변수가 구체적인 타입이기 때문
메서드 오버로딩은 스테틱 디스패치가 이루어지기 때문에 컴파일 시점에 매개변수의 타입을 정확하게
지정해두어야한다.
매서드 오버로딩일 일어나기 위해선 스태틱 디스패치를 해야하는데 주어진 정보만 가지고는
어느메서드를 실행해야하는지 잡을 수 없다.
다이나믹 디스패칭 시 다이나믹 조건이 파라미터에 걸려있기때문에 실행되지 않음 : 파라미터는 다이나믹 디스패치의 조건이 되지않는다.
-> 이를 해결하기 위해선 다형성을 두번 적용하는 과정이 필요함
*/
// Post
interface Post {
// 2. 메서드 오버로딩과 매개변수 타입 구체화 추가
void postOn(Facebook sns);
void postOn(Twitter sns);
}
static class Text implements Post {
// 문제 지점
// 2. 메서드 오버로딩과 매개변수 타입 구체화 추가
public void postOn(Facebook sns) {
System.out.println("text-facebook");
}
public void postOn(Twitter sns) {
System.out.println("text-twitter");
}
}
static class Picture implements Post {
// 2. 메서드 오버로딩과 매개변수 타입 구체화 추가
public void postOn(Facebook sns) {
System.out.println("picture-facebook");
}
public void postOn(Twitter sns) {
System.out.println("picture-twitter");
}
}
// SNS
interface SNS{
}
static class Facebook implements SNS {
};
static class Twitter implements SNS {
};
// main
public static void main(String[] args) {
List<Post> posts = Arrays.asList(new Text(),new Picture());
List<SNS> sns = Arrays.asList(new Facebook(),new Twitter() // , new GooglePlus()
);
// 에러발생
// 다이나믹 디스패치 수행 : 이중 for 문
// posts.forEach( p -> sns.forEach( s -> p.postOn(s)));
// ==
// posts.forEach((Post p) -> sns.forEach((SNS s) -> p.postOn(s)));
}
}
public class SNSThird {
/*
3. 객체지향스러운 결과 : SNS 를 새로 추가하는것이 자유롭고 코드를 추가하는 시점에서 의존하는 코드(Post 측)에 직접적인 영향을 주지 않음
단, Post 측의 변경이 일어날때는 다른 고민이 필요함
*/
// Post
interface Post {
// 3. 다시 원상복귀 SNS 타입으로 받는다.
void postOn(SNS sns);
}
static class Text implements Post {
// 문제 지점
// 3. 구현을 SNS 로 옮긴다.
public void postOn(SNS sns) {
sns.post(this); // sns의 post 를 호출하고 자기 자신을 넘기도록 구현
// 다이나믹 디스패칭 시점 2. : sns 에 대한 다이나믹 디스패칭이 일어남
}
}
static class Picture implements Post {
// 문제 지점
// 3. 구현을 SNS 로 옮긴다.
public void postOn(SNS sns) {
sns.post(this); // sns의 post 를 호출하고 자기 자신을 넘기도록 구현
// 다이나믹 디스패칭 시점 2. : sns 에 대한 다이나믹 디스패칭이 일어남
}
}
// SNS
interface SNS{
// 3. 메서드 추가
void post(Text post);
void post(Picture post);
}
static class Facebook implements SNS {
// 3. 구현 추가
public void post(Text post) {
System.out.println("text-facebook");
}
// 3. 구현 추가
public void post(Picture post) {
System.out.println("picture-facebook");
}
};
static class Twitter implements SNS {
// 3. 구현 추가
public void post(Text post) {
System.out.println("text-twitter");
}
// 3. 구현 추가
public void post(Picture post) {
System.out.println("picture-twitter");
}
};
// 새로운 SNS 추가
static class GooglePlus implements SNS {
// 3. 구현 추가
public void post(Text post) {
System.out.println("text-google plus");
}
// 3. 구현 추가
public void post(Picture post) {
System.out.println("picture-google plus");
}
};
// main
public static void main(String[] args) {
List<Post> posts = Arrays.asList(new Text(),new Picture());
List<SNS> sns = Arrays.asList(new Facebook(),new Twitter() ,new GooglePlus());
// 에러발생
// 다이나믹 디스패치 수행
posts.forEach( p -> sns.forEach( s -> p.postOn(s))); // 다이나믹 디스패칭 시점 1.
// ==
// posts.forEach((Post p) -> sns.forEach((SNS s) -> p.postOn(s)));
}
}