2012-08-24 5 views
0

나는 빈을 확장 여러 개체했습니다 :특정 클래스를 기반으로 특정 구현을 인스턴스화하는 방법은 무엇입니까?

public class Fruit {} 

public class Banana extends Fruit {} 

public class Pear extends Fruit {} 

을 그리고 다른 구현, 각 빈에 대한 하나의 인터페이스를했습니다.

public interface Milkshake { 
    public String doMilkshake(); 
} 

public class FruitMilkshake implements Milkshake { 
    public String doMilkshake() { 
     return "Fruit Milkshake!"; 
    } 
} 

public class BananaMilkshake implements Milkshake { 
    public String doMilkshake() { 
     return "Banana Milkshake!"; 
    } 
} 

public class PearMilkshake implements Milkshake { 
    public String doMilkshake() { 
     return "Pear Milkshake!"; 
    } 
} 

콩의 구체적인 유형을 기반으로 올바른 구현을 어떻게 인스턴스화 할 수 있습니까?

필자는 타이핑과 맵을 사용하여 올바른 구현을 "매핑"했습니다. 이를 달성하기 위해 더 나은

public void hungry(Fruit fruit) { 
    Map<String, String> obj2impl = new HashMap<String, String>(); 
    obj2impl.put("Fruit", "FruitMilkshake"); 
    obj2impl.put("Banana", "BananaMilkshake"); 
    obj2impl.put("Pear", "PearMilkshake"); 

    String name = fruit.getClass().getCanonicalName(); 
    String implName = obj2impl.get(name); 
    Milkshake milkshake = (Milkshake) Class.forName(implName).newInstance(); 

    milkshake.doMilkshake(fruit); 
} 



public interface Milkshake <T t> { 
    public String doMilkshake(T t); 
} 

public class FruitMilkshake implements Milkshake<Fruit> { 
    public String doMilkshake(Fruit fruit) { 
     return "Fruit Milkshake!"; 
    } 
} 

public class BananaMilkshake implements Milkshake<Banana> { 
    public String doMilkshake(Banana banana) { 
     return "Banana Milkshake!"; 
    } 
} 

public class PearMilkshake implements Milkshake<Pear> { 
    public String doMilkshake(Pear pear) { 
     return "Pear Milkshake!"; 
    } 
} 

방법 : 이것처럼 ?

+0

'배가 고프다'할 때마다 과일 맵을 다시 만들어서는 안됩니다. 이 맵을 대신 인스턴스 변수로 넣으십시오. 또는 과일 이름을 켭니다. – maba

답변

1

이 방법을 더 효과적으로 구현할 수 있습니까? 항상를 작성

Map<String, Class<? extends Milkshake>> obj2impl = 
    new HashMap<String, Class<? extends Milkshake>>(); 
obj2impl.put("Fruit", FruitMilkshake.class); 
obj2impl.put("Banana", BananaMilkshake.class); 

... 

Milkshake milkshake = obj2impl.get(text).newInstance(); 

이제 여전히 각 구현에서 매개 변수가없는 생성자를 가질 것을 요구하고 여전히 :

잘 출발점은 클래스의 이름에 반영하지 않도록하는 것입니다 새로운 인스턴스. 게시물을 다시 읽어 데, 당신은뿐만 아니라 텍스트 부분을 제거 할 수 및 Map<Class<?>, Provider<Milkshake>> 있습니다

Map<String, Provider<Milkshake>> map = ...; 
// Fill the map with providers, some of which could create a new instance, 
// and some could reuse an existing one 

... 

Milkshake milkshake = map.get(text).get(); 

편집 : 당신이 Provider -like 개념을 사용하는 경우,이 피해 갈 수 있습니다. 가능한 경우 클래스의 이름을 하드 코딩하지 마십시오. 당신의 Fruit 클래스는 makeMilkshake 추상적 인 방법이 있다면 물론

는 그

+0

분명히 그 이름을 사용하지는 않습니다. 그것은 단지 예일뿐입니다. – Enrichman

+1

@Enrichman : 실제 이름 인 것은 아니지만 대신 클래스 리터럴을 사용할 수있을 때지도의 클래스 이름 * 텍스트 *를 사용하고 있습니다. 그것이 내 요점이다. –

+0

아, 알았어. 네가 옳아. :) Btw 나는 내 프로젝트에서 Guice를 사용하여 공급자 물건이 유용 할 것입니다. IoC 만 제가 생각하는 유일한 방법입니다. – Enrichman

0
public class Fruit { 
    public Class<? extends Milkshake> getMilkshakeClass() { 
     return Milkshake.class; 
    } 
} 

public class Banana extends Fruit { 
    public Class<? extends Milkshake> getMilkshakeClass() { 
     return Banana.class; 
    } 
} 

public class Pear extends Fruit { 
    public Class<? extends Milkshake> getMilkshakeClass() { 
     return PearMilkshake.class; 
    } 
} 

심지어 추상적으로 위에 사용 된 방법이있는 AbstractFruit 클래스를 만들 수도 있습니다 ... 심지어 더 좋은 것 그들이 재정의해야하는 방법

public abstract class AbstractFruit { 
    public abstract Class<? extends Milkshake> getMilkshakeClass(); 
} 

과일을 확장시키는 것보다는 확장하는 것이 좋습니다.

+0

이제 '밀크 셰이크'에 대한 지식을 얻기 위해 '과일, 바나나 및 배'를 묶습니다. 왜 그들은 밀크 셰이크에 대한 지식이 있습니까? – maba

+0

과일을 가지고 밀크 쉐이크를 할 수 있으니? 그것은 완전히 그럴듯한 생각입니다. 그는 그들이 가지고있는 서로에 대한 정확한 지식을 말하지 않았지만 모두 공개적입니다. 그래서 그들은 모두 서로를 알고 있다고 생각합니다. –

+0

그리고 칵테일이나 잼을 만들 수 있습니다. – maba

관련 문제