2017-11-19 1 views
4

를 구현하는 일반적인 클래스의 정적 기능을 지원합니다. 인터페이스 Operations의 기능에 따라 위치 계산이 걸릴 것최고의 디자인 패턴은 내가 인터페이스 <code>Operations</code>이 인터페이스

// simple implementation without type check etc.. 
public final class MyInteger implements Operations{ 
    private final int delegate; 

    public MyInteger(int i){ 
     delegate = i; 
    } 

    @Override 
    Operations add(Operations other){ 
     return new MyInteger(delegate + ((MyInteger) other).delegate); 
    } 
    @Override 
    Operations subtract(Operations other){ 
     return new MyInteger(delegate - ((MyInteger) other).delegate); 
    } 
    (...) 
} 

다른 클래스에서 예를 들어 사용자는 단지 그가 클래스 MyInteger를 사용할 수있는 데이터 유형 Integer와 기본 조작을 사용하고자합니다.

public class Calculation<D extends Operations> { 

    private final D value1, value2; 
    private final D value3 = D.valueOf(4); // cannot implement this in interface 

    public Calculation(D value1, D value2){ 
     this.value1 =value1; 
     this.value2 = value2; 
    } 

    public D sumPlusValue3(){ 
     return value1.plus(value2).plus(value3); 
    } 
} 

그래서

Calculation<MyInteger> calc = new Calculation<MyInteger>(new MyInteger(1), new MyInteger(2)); 
Operations result = calc.sumPlusValue3(); 

:하지만 가끔은 내가이 예에서와 같이, 그래서 주어진 문자열, 더블, INT에 해당하는 클래스의 구현을 반환하고 valueOf(val) 기능과 같은 정적 컨텍스트를 필요 내가 생각 일반적으로 내가

Operations integerImpl = OperationsBuilder.create("Integer"); 
처럼 사용자가 자신이 원하는 어떤 구현 지정할 수 있도록 Builder 또는 Factory 같은 디자인 패턴을 사용해야합니다

그러나 이러한 패턴을 연구 한 후에도 클래스에 value3에 대한 일반 클래스 D의 구현을 얻는 명확한 방법을 찾을 수 없습니다.

EDIT 1은 :

나는 질문을 편집하고 내 문제에 대한 최선의 해결책이기 때문에 @Stefan HAUSTEIN에서 답을 표시했다. 그러나 @davidxxx의 답은 초기 질문과 관련하여 좋은 대답이기도합니다 - 을 나타내는 방법은valueOf(int val)입니다. Calculation 당신이 항상 근처 어쨌든 D의 인스턴스가있는 경우 기술적으로는 해당 값을 필요로하지 않지만

+0

'int'를'double'에 추가하고 싶습니다. 가능합니까?'Operation ' – Andrew

+0

아니요, 가능하지 않아야합니다. 즉, 모든 운영 구현이 동일한 인스턴스에 속해 있는지 확인해야합니다. Calculations 클래스에서 이는 generic 매개 변수 때문에 충족 되었습니까? – team17

답변

1

, 당신은 단지 valueOfOperations의 비 정적 멤버를 만들 수 있습니다.

valueOf에 "더미"인스턴스를 사용할 수없는 경우 Calculations의 생성자 매개 변수로 Class<D>이 필요합니다. 그러면 중립 요소를 제공하는 newInstance()에 전화 할 수 있습니다. 그러나 구체적인 값을 얻으려면 여전히 addInt과 같은 작업이 필요합니다. 이러한 아이디어는 명백한 더미 값의 필요성을 피하기 위해 결합 될 수 있습니다.

또 다른 옵션은, 더미 인스턴스에서 종속성을 피하고 계산 인스턴스 생성에 부담을 이동 Calculation에서 valueOf 추상적하게하는 것입니다 : 일반적으로

Calculation<MyInteger> calc = new Calculation<MyInteger>(
    new MyInteger(1), new MyInteger(2)) { 
     public MyInteger valueOf(int i) { 
     return new MyInteger(i); 
     } 
    }); 

Operations result = calc.sumPlusValue3(); 

,이 적절한 균형에 대해 것 같다 "순도"와 "여분의 층/복잡성"사이. 순도를 희생하면서, 더 실용적이고 오버 헤드를 피하는 방향으로 기울여야합니다.

P....

public final class MyInteger implements Operations{ 
    private final int delegate; 

    public static final OperationsFactory<MyInteger> FACTORY = 
    new OperationsFactory<>() { 
     @Override 
     MyInteger valueOf(int i) { 
     return new MyInteger(i); 
     } 
    }; 

    public MyInteger(int i){ 
     delegate = i; 
    } 

    @Override 
    Operations add(Operations other){ 
     return new MyInteger(delegate + ((MyInteger) other).delegate); 
    } 
    @Override 
    Operations subtract(Operations other){ 
    return new MyInteger(delegate - ((MyInteger) other).delegate); 
    } 
    (...) 
} 

이 적어도 함께 하나 개의 파일에 모든 것을 구현 측을 유지하는 것 : 또 다른 옵션은 명시 적 팩토리 인터페이스를 가지고 있지만, 컨벤션 등의 작업 클래스의 필드로 저장할 수 있습니다

+0

같은 몇 가지 valueOf 함수를 사용해야하는 경우 : D valueOf (String val), D valueOf (double val) 인스턴스 함수로 가져와 머리글을 일반 매개 변수 (예 : davidxxx 답변)? 나도 몰라,하지만 다른 값을 저장하는 인스턴스에서 'valueOf (val)'함수를 사용하는 것이 조금 더러운 것처럼 보입니다 ... – team17

+0

너무 많은 값이있는 경우 팩토리 인터페이스를 분리합니다. 이 인스턴스가 하나만 필요하다고 가정하면 정적 필드로 구현에 넣을 수 있습니다. 추가 예제 –

+0

을 참조하십시오. 그러나 'Calculate'클래스에서 'D'구현을 알지 못하므로 잘 모릅니다. 어느 공장을 사용해야합니까? 예를 들어 'Operations'의 다른 구현이 존재합니다. 'MyDouble.FACTORY.valueOf (..)'또는 MyInteger.FACTORY.valueOf (..)를 호출해야하는지 잘 모르는 것보다 'MyDouble' – team17

2

1) 초기 문제 : 공장 호출 여기

:

private final D value3 = D.valueOf(4); // cannot implement this in interface 

을 당신은 일반적인 그쪽으로 값 value3을 원하는 t는 공장이 아닙니다.
인터페이스에서 (인스턴스 메소드처럼) valueOf()을 정의하는 것은 해결책이 아닙니다.

대안으로 value3 값을 갖는 방법을 사용하기 위해 Calculation 생성자에 팩토리 매개 변수를 도입 할 수 있습니다.

private final D value3 = D.valueOf(4); 

public Calculation(D value1, D value2){ 
    this.value1 =value1; 
    this.value2 = value2; 
} 

에 의해 :

private final D value3; 

public Calculation(D value1, D value2, FactoryD factoryD){ 
    this.value1 =value1; 
    this.value2 = value2; 
    this.value3 = factoryD.create(4); 
} 

을하거나 더 나은 공장의 Function 기능 인터페이스를 사용

그래서 대체

private final D value3; 

public Calculation(D value1, D value2, IntFunction<D> factoryD){ 
    this.value1 =value1; 
    this.value2 = value2; 
    this.value3 = factoryD.apply(4); 
} 

당신은 그래서처럼 사용할 수 있습니다

Calculation<MyInteger> calc = new Calculation<>(new MyInteger(1), new MyInteger(2), MyInteger::new); 
Operations result = calc.sumPlusValue3(); 

그러나 Operations은 뭔가를 놓칩니다.

2) Operations 값을 나타낼 방법이 없습니다.

public interface Operations{ 

    Operations add(Operations op); 

    Operations subtract(Operations op); 
} 

당신은 오히려 가치를 얻을 및 모든 유형의 값을 처리하는 인터페이스는 일반적인 만들 수있는 방법을 정의해야합니다 :

사실, Operations 조작 방법 만 개체 값을 표시 할 수있는 방법을 정의

public interface Operations<T> { 

    Operations<T> add(Operations<T> op); 

    Operations<T> subtract(Operations<T> op); 

    T getValue(); 

} 

MyInteger 정도로 정의 될 수

public final class MyInteger implements Operations<Integer> { 

    private final int delegate; 

    public MyInteger(int i) { 
     delegate = i; 
    } 

    @Override 
    public Operations<Integer> add(Operations<Integer> other) { 
     return new MyInteger(delegate + other.getValue()); 
    } 

    @Override 
    public Operations<Integer> subtract(Operations<Integer> other) { 
     return new MyInteger(delegate - other.getValue()); 
    } 

    @Override 
    public Integer getValue() { 
     return delegate; 
    } 
} 
012,351 Operations에 대한 하나 Operations 반환 형식에 대한 또 다른 :

Calculation<Integer, MyInteger> calc = new Calculation<>(new MyInteger(1), new MyInteger(2), MyInteger::new); 
Operations<Integer> result = calc.sumPlusValue3(); 
System.out.println(result.getValue()); 

출력 :

당신은 너무 이런 식으로이 코드를 사용할 수 있습니다

public class Calculation<C, D extends Operations<C>> { 

    private final D value1, value2; 
    private final D value3; 

    public Calculation(D value1, D value2, IntFunction<D> factoryD){ 
     this.value1 =value1; 
     this.value2 = value2; 
     this.value3 = factoryD.apply(4); 
    } 

    public Operations<C> sumPlusValue3(){ 
     return value1.add(value2).add(value3); 
    }   
} 

6,

그리고 Calculation은 그래서 두 개의 제네릭으로 정의 할 수 있습니다

7

+0

반환 형식 힌트를 가져 주셔서 감사합니다. 나는 또한 일반적인 함수/IntFunction을 사용하는 접근법을 좋아한다. 나에 대한 단점은 내가 추가 매개 변수를 가지고 내가 다른 가치, 예를 들어, D valueOf (String val), D valueOf (Int val), ... 당신은 인스턴스 함수가 ​​더 적합하다고 말할 것입니다 이 경우? – team17

+0

당신은 오신 것을 환영합니다. D 인스턴스를 생성하기 위해'Calculation'에서 숫자 값을 하드 코딩 한 것처럼'IntFunction'을 제안했습니다 :'this.value3 = factoryD.apply (4);'D 인스턴스를 생성하기 위해 어떤 타입을 건네주기를 원한다면, 'Function '함수를 지정할 수 있습니다. 물론'Calculation' 클래스에서는'C' 타입이'Function' 에서처럼'C' 타입을 참조해야하고 숫자 또는'String' 값이 아닌 특정 타입이 아닌 generic을 참조해야합니다. – davidxxx

관련 문제