두 개의 인터페이스가 있는데, 둘 다 목적이 다르지만 동일한 메서드 서명을 사용하는 경우 인터페이스 모두에 사용되는 단일 메서드를 작성하지 않고 메서드에 복잡한 논리를 작성하지 않고 클래스를 둘 다 구현하도록하려면 어떻게해야합니까? 어떤 유형의 객체가 호출되고 있는지 확인하고 적절한 코드를 호출하는 구현?
C #에서 이것은 명시 적 인터페이스 구현이라고하는 것에 의해 극복됩니다. Java에 동등한 방법이 있습니까?
두 개의 인터페이스가 있는데, 둘 다 목적이 다르지만 동일한 메서드 서명을 사용하는 경우 인터페이스 모두에 사용되는 단일 메서드를 작성하지 않고 메서드에 복잡한 논리를 작성하지 않고 클래스를 둘 다 구현하도록하려면 어떻게해야합니까? 어떤 유형의 객체가 호출되고 있는지 확인하고 적절한 코드를 호출하는 구현?
C #에서 이것은 명시 적 인터페이스 구현이라고하는 것에 의해 극복됩니다. Java에 동등한 방법이 있습니까?
답변:
아니요, Java의 한 클래스에서 두 가지 다른 방법으로 동일한 메서드를 구현할 수있는 방법이 없습니다.
이는 많은 혼란스러운 상황을 초래할 수 있으며, 이것이 Java가이를 허용하지 않은 이유입니다.
interface ISomething {
void doSomething();
}
interface ISomething2 {
void doSomething();
}
class Impl implements ISomething, ISomething2 {
void doSomething() {} // There can only be one implementation of this method.
}
할 수있는 일은 각각 다른 인터페이스를 구현하는 두 개의 클래스로 클래스를 구성하는 것입니다. 그러면 한 클래스가 두 인터페이스의 동작을 갖게됩니다.
class CompositeClass {
ISomething class1;
ISomething2 class2;
void doSomething1(){class1.doSomething();}
void doSomething2(){class2.doSomething();}
}
ISomething1 CompositeClass.asInterface1();
and ISomething2 CompositeClass.asInterface2();
메소드를 추가하는 것입니다. 그런 다음 복합 클래스에서 하나 또는 다른 하나를 가져올 수 있습니다. 하지만이 문제에 대한 훌륭한 해결책은 없습니다.
public long getCountAsLong() implements interface2.getCount {...}
[인터페이스에 a가 필요 long
하지만 클래스 사용자가 예상하는 경우 int
] 또는 private void AddStub(T newObj) implements coolectionInterface.Add
[ 메서드 collectionInterface
가 있다고 가정 canAdd()
하고이 클래스의 모든 인스턴스에 대해 반환하는 경우 false
] 와 같은 것을 허용하는 것이 실제로 얼마나 혼란 스러울 까요?
Java에서이 문제를 해결할 실제 방법은 없습니다. 해결 방법으로 내부 클래스를 사용할 수 있습니다.
interface Alfa { void m(); }
interface Beta { void m(); }
class AlfaBeta implements Alfa {
private int value;
public void m() { ++value; } // Alfa.m()
public Beta asBeta() {
return new Beta(){
public void m() { --value; } // Beta.m()
};
}
}
에서 AlfaBeta
으로의 캐스트를 허용하지 않지만 Beta
다운 캐스트는 일반적으로 악의적이며 Alfa
인스턴스에도 종종 Beta
측면 이 있을 것으로 예상 될 수 있으며 어떤 이유로 (일반적으로 최적화가 유일한 유효한 이유입니다) 할 수 있기를 원합니다. 로 변환하려면 with Beta
의 하위 인터페이스를 만들 수 있습니다.Alfa
Beta asBeta()
이 문제가 발생하면 delegation 을 사용해야하는 곳에 상속을 사용하고 있기 때문일 가능성이 큽니다 . 동일한 기본 데이터 모델에 대해 비슷하지만 서로 다른 두 개의 인터페이스를 제공 해야하는 경우 다른 인터페이스를 사용하여 데이터에 대한 액세스를 저렴하게 제공하기 위해 뷰 를 사용해야합니다 .
후자의 경우에 대한 구체적인 예를 제공하기 위해 Collection
및 MyCollection
(상속되지 않고 Collection
호환되지 않는 인터페이스가 있음) 둘 다를 구현한다고 가정합니다 . 동일한 기본 데이터를 사용하여 및 의 간단한 구현을 제공하는 Collection getCollectionView()
및 MyCollection getMyCollectionView()
함수를 제공 할 수 있습니다 .Collection
MyCollection
전자의 경우 ... 정말로 정수 배열과 문자열 배열을 원한다고 가정합니다. List<Integer>
및 둘 다에서 상속하는 대신 List<String>
유형의 멤버 하나와 유형의 List<Integer>
다른 멤버가 List<String>
있어야하며 둘 다에서 상속하려고하지 말고 해당 멤버를 참조해야합니다. 정수 목록 만 필요하더라도이 경우 상속보다 합성 / 위임을 사용하는 것이 좋습니다.
"고전적인"Java 문제는 Android 개발에도 영향을 미칩니다 ...
그 이유는 간단 해 보입니다.
더 많은 프레임 워크 / 라이브러리를 사용해야하며, 더 쉽게 제어 할 수 없습니다
. 제 경우에는 BootStrapperApp 클래스가 있습니다. android.app.Application 에서 상속
되지만 동일한 클래스는 통합을 위해 MVVM 프레임 워크 의 Platform 인터페이스 도 구현해야합니다 . getString () 메서드
에서 메서드 충돌이 발생했습니다.이 메서드는 두 인터페이스에 의해 발표되고 다른 컨텍스트에서 다른 구현을 가져야합니다.
해결 방법 (ugly..IMO)은 내부 클래스를 사용하여 모든 플랫폼 을 구현하는 것입니다.
메서드, 단지 하나의 사소한 메서드 서명 충돌 때문에 ... 어떤 경우에는 그러한 빌린 메서드가 전혀 사용되지도 않습니다 (그러나 주요 디자인 의미에 영향을 미침).
나는 C # 스타일의 명시 적 컨텍스트 / 네임 스페이스 표시가 도움이된다는 데 동의하는 경향이 있습니다.
내 마음에 떠오른 유일한 해결책은 다중 인터페이스를 단순화하려는 객체에 대한 참조 객체를 사용하는 것입니다.
예 : 구현할 인터페이스가 2 개 있다고 가정합니다.
public interface Framework1Interface {
void method(Object o);
}
과
public interface Framework2Interface {
void method(Object o);
}
두 개의 Facador 객체로 묶을 수 있습니다.
public class Facador1 implements Framework1Interface {
private final ObjectToUse reference;
public static Framework1Interface Create(ObjectToUse ref) {
return new Facador1(ref);
}
private Facador1(ObjectToUse refObject) {
this.reference = refObject;
}
@Override
public boolean equals(Object obj) {
if (obj instanceof Framework1Interface) {
return this == obj;
} else if (obj instanceof ObjectToUse) {
return reference == obj;
}
return super.equals(obj);
}
@Override
public void method(Object o) {
reference.methodForFrameWork1(o);
}
}
과
public class Facador2 implements Framework2Interface {
private final ObjectToUse reference;
public static Framework2Interface Create(ObjectToUse ref) {
return new Facador2(ref);
}
private Facador2(ObjectToUse refObject) {
this.reference = refObject;
}
@Override
public boolean equals(Object obj) {
if (obj instanceof Framework2Interface) {
return this == obj;
} else if (obj instanceof ObjectToUse) {
return reference == obj;
}
return super.equals(obj);
}
@Override
public void method(Object o) {
reference.methodForFrameWork2(o);
}
}
결국 당신이 원하는 수업은 다음과 같아야합니다.
public class ObjectToUse {
private Framework1Interface facFramework1Interface;
private Framework2Interface facFramework2Interface;
public ObjectToUse() {
}
public Framework1Interface getAsFramework1Interface() {
if (facFramework1Interface == null) {
facFramework1Interface = Facador1.Create(this);
}
return facFramework1Interface;
}
public Framework2Interface getAsFramework2Interface() {
if (facFramework2Interface == null) {
facFramework2Interface = Facador2.Create(this);
}
return facFramework2Interface;
}
public void methodForFrameWork1(Object o) {
}
public void methodForFrameWork2(Object o) {
}
}
이제 getAs * 메소드를 사용하여 클래스를 "노출"할 수 있습니다.
문제의 모든 코드를 완전히 제어 할 수 있고이를 미리 구현할 수있을 때 모두 훌륭하고 좋습니다. 이제 메서드를 사용하여 여러 곳에서 사용되는 기존 공용 클래스가 있다고 가정합니다.
public class MyClass{
private String name;
MyClass(String name){
this.name = name;
}
public String getName(){
return name;
}
}
이제 WBPInterface ...를 구현하는 클래스가 필요한 선반 WizzBangProcessor로 전달해야합니다. WBPInterface ...도 getName () 메서드가 있지만 구체적인 구현 대신이 인터페이스는 메서드가 형식의 이름을 반환 할 것으로 예상합니다. Wizz Bang Processing의.
C #에서는 trvial입니다.
public class MyClass : WBPInterface{
private String name;
String WBPInterface.getName(){
return "MyWizzBangProcessor";
}
MyClass(String name){
this.name = name;
}
public String getName(){
return name;
}
}
Java Tough에서는 한 인터페이스에서 다른 인터페이스로 변환해야하는 기존 배포 된 코드베이스의 모든 지점을 식별해야합니다. 물론 WizzBangProcessor 회사는 getWizzBangProcessName ()을 사용 했어야하지만 그들도 개발자입니다. 그들의 맥락에서 getName은 괜찮 았습니다. 실제로 Java 외부에서는 대부분의 다른 OO 기반 언어가이를 지원합니다. Java는 모든 인터페이스가 동일한 메소드 NAME로 구현되도록하는 경우는 드뭅니다.
대부분의 다른 언어에는 "이 구현 된 인터페이스에서이 메서드의 시그니처와 일치하는이 클래스의 메서드가 바로 구현입니다"라고 말하는 명령을받는 것보다 더 행복한 컴파일러가 있습니다. 인터페이스 정의의 모든 요점은 정의가 구현에서 추상화되도록 허용하는 것입니다. (기본 재정의는 말할 것도없고 Java의 인터페이스에서 기본 메서드를 시작하지도 마십시오. 그들은 둘 다 자동차입니다 ... 자동차 만 yaw!