문제

비교 기준을 비교하려고합니다. '사이에'와 'inarray'또는 'Greaterthan'과 같은 단순한 것. 나는이 클래스에 다형성을 사용합니다. 비교 기준 인터페이스에서 공유하는 한 가지 방법은 'MatchCompareCriteria'입니다.

내가 피하려고하는 것은 각 수업이 비교하는 비교기 유형을 확인하는 것입니다. 예를 들어, Inarray 객체는 MatchCompareCriteria가 inarray 객체가 전달되는지 확인합니다. 그렇지 않으면 False를 반환하지 않으면 비교하는 방법을 알고 있습니다.

이 경우 인스턴스가 완벽하게 합법적 일 수도 있지만 (물체는 자신에 대해 알고 있습니다) 여전히 피할 수있는 가능한 방법을 찾고 있습니다. 어떤 아이디어?

의사 코드 예 :

betweenXandY = create new between class(x, y)
greaterThanZ = create new greaterThan class(z)
greaterThanZ.matchCompareCriteria(betweenXandY)

x와 y가 z보다 크면 true가 반환됩니다.

편집하다:

1) 인스턴스의 인스턴스는 현재 MatchCompareCriteria 방법에서 필요에 따라 내가 보는 것입니다. 제거하고 싶습니다

2) MatchCompareCritera는 비교 문자가 다른 사람에 의해 포함되어 있는지 확인합니다. 하나의 가능한 모든 값이 다른 값에 포함 된 경우 TRUE를 반환합니다. 비교기의 많은 조합의 경우 비교하는 것이 합리적이지 않아서 거짓을 반환하여 (알파 사이와 종교 간은 양립 할 수 없음)를 반환합니다.

도움이 되었습니까?

해결책

당신이 설명하는 문제를 호출합니다 이중 파견. 이름은 두 객체의 유형 (따라서 Double)에 따라 어떤 코드를 실행할 것인지 결정해야한다는 사실에서 비롯됩니다.

일반적으로 OO에는 단일 디스패치가 있습니다. 객체에 대한 메소드를 호출하면 객체가 방법을 실행할 수있는 원인입니다.

귀하의 경우에는 두 개의 객체가 있으며 실행될 구현은 두 객체의 유형에 따라 다릅니다. 기본적으로, 이전에 표준 OO 상황을 다루었을 때 "잘못된 느낌"이라는 커플 링이 암시됩니다. 그러나 그것은 실제로 잘못된 것이 아닙니다. OO의 기본 기능이 해결에 직접적으로 적합한 문제 영역의 약간 밖에 있습니다.

동적 언어 (또는 반사가있는 정적 유형 언어,이 목적을 위해 충분히 동적)를 사용하는 경우 기본 클래스에서 디스패처 메소드로이를 구현할 수 있습니다. 의사 코드에서 :

class OperatorBase
{
    bool matchCompareCriteria(var other)
    {
        var comparisonMethod = this.GetMethod("matchCompareCriteria" + other.TypeName);
        if (comparisonMethod == null)
            return false;

        return comparisonMethod(other);
    }
}

여기서 나는 언어가 모든 클래스에서 내장 된 방법을 가지고 있다고 상상하고 있습니다. GetMethod 이를 통해 이름으로 메소드와 객체 유형의 이름을 얻는 모든 객체의 타입 이름 속성도 찾아 낼 수 있습니다. 따라서 다른 클래스가 a GreaterThan, 및 파생 클래스에는 MatchCompareCriteriageReaterthan이라는 메소드가 있습니다.이 방법을 호출합니다.

class SomeOperator : Base
{
    bool matchCompareCriteriaGreaterThan(var other)
    {
        // 'other' is definitely a GreaterThan, no need to check
    }
}

따라서 올바른 이름의 메소드를 작성하면 파견이 발생합니다.

인수 유형별로로드 메소드 과부하를 지원하는 정적으로 입력 한 언어에서는 연결된 명명 규칙을 발명하지 않아도됩니다. 예를 들어, 여기에는 C#:

class OperatorBase
{
    public bool CompareWith(object other)
    {
        var compare = GetType().GetMethod("CompareWithType", new[] { other.GetType() });
        if (compare == null)
            return false;

        return (bool)compare.Invoke(this, new[] { other });
    }
}

class GreaterThan : OperatorBase { }
class LessThan : OperatorBase { }

class WithinRange : OperatorBase
{
    // Just write whatever versions of CompareWithType you need.

    public bool CompareWithType(GreaterThan gt)
    {
        return true;
    }

    public bool CompareWithType(LessThan gt)
    {
        return true;
    }
}

class Program
{
    static void Main(string[] args)
    {
        GreaterThan gt = new GreaterThan();
        WithinRange wr = new WithinRange();

        Console.WriteLine(wr.CompareWith(gt));
    }
}

모델에 새 유형을 추가하려면 이전 유형의 모든 유형을보고 어떤 방식 으로든 새로운 유형과 상호 작용 해야하는지 스스로에게 물어봐야합니다. 따라서 모든 유형은 상호 작용 방법을 정의해야합니다 그 밖의 모든 유형 - 상호 작용이 정말 간단한 기본값 인 경우에도 (예 : "반품을 제외하고는 아무것도하지 마십시오. true"). 단순한 기본값조차도 의도적 인 선택을 나타냅니다. 이것은 가장 일반적인 경우에 대한 코드를 명시 적으로 작성하지 않아도되는 편의에 의해 위장됩니다.

따라서 모든 객체 주위에 산란하는 대신 외부 테이블의 모든 유형 간의 관계를 캡처하는 것이 더 합리적 일 수 있습니다. 중앙 집중화의 가치는 유형 간의 중요한 상호 작용을 놓친지를 즉시 확인할 수 있다는 것입니다.

따라서 다른 사전에 유형을 매핑하는 사전/지도/해시 가능 (언어로 불리는)을 가질 수 있습니다. 두 번째 사전은이 두 유형의 두 번째 유형을 올바른 비교 함수에 맵핑합니다. 일반 비교 기능은 해당 데이터 구조를 사용하여 호출 할 올바른 비교 기능을 찾습니다.

어떤 접근법이 올바른지 모델에서 끝날 가능성이 얼마나 많은지에 따라 다릅니다.

다른 팁

당신이 참조하기 때문에 instanceof, 나는 우리가 여기에서 Java에서 일하고 있다고 가정하고 있습니다. 이렇게하면 과부하를 사용할 수 있습니다. 호출 된 인터페이스를 고려하십시오 SomeInterface, 단일 방법이있는 다음과 같습니다.

public interface SomeInterface {
    public boolean test (SomeInterface s);
}

이제 우리는 구현하는 두 개의 (영리한 명명) 클래스를 정의합니다. SomeInterface: Some1 그리고 Some2. Some2 지루하다 : test 항상 거짓을 반환합니다. 그러나 일부 1은 test 주어진 경우 기능 Some2:

public class Some1 implements SomeInterface {
    public boolean test (SomeInterface s) {
        return false;
    }

    public boolean test (Some2 s) {
        return true;
    }
}

이렇게하면 IF 문의 선을 따라 유형 확인을 수행 할 수 있습니다. 그러나 경고가 있습니다. 이 코드를 고려하십시오.

Some1 s1 = new Some1 ();
Some2 s2 = new Some2 ();
SomeInterface inter = new Some2 ();

System.out.println(s1.test(s2));     // true
System.out.println(s2.test(s1));     // false
System.out.println(s1.test(inter));  // false

그 세 번째 테스트가 보이십니까? 일지라도 inter 유형입니다 Some2, 그것은 a로 취급됩니다 SomeInterface 대신에. 과부하 해상도는 Java의 컴파일 타임에서 결정되므로 완전히 쓸모가 없습니다.

그것은 당신을 Square One으로 돌아갑니다 : 사용 instanceof (런타임에 평가됩니다). 그렇게하더라도 여전히 나쁜 디자인입니다. 각 수업은 다른 수업에 대해 알아야합니다. 다른 것을 추가하기로 결정한 경우, 새로운 클래스를 처리하기 위해 기능을 추가하려면 기존의 모든 것들로 돌아 가야합니다. 이것은 서두르면서 끔찍하게 유지할 수 없게됩니다. 이는 디자인이 나쁘다는 좋은 신호입니다.

재 설계는 순서대로 진행되지만 더 많은 정보가 없으면 올바른 방향으로 진정으로 잘 밀기를 줄 수는 없습니다.

Criteria라는 슈퍼 클래스 또는 인터페이스를 만들어야합니다. 그러면 각 콘크리트 하위 클래스는 기준 인터페이스를 구현합니다. 그 사이에 더 큰 등은 기준입니다.

기준 클래스는 기준을 수락하는 MatchCompareCriteria 메소드를 지정합니다. 실제 논리는 하위 클래스에 있습니다.

전략 디자인 패턴 또는 템플릿 디자인 패턴을 찾고 있습니다.

잘 이해하면 방법은 유형 확인에 의존합니다. 그것은 피하기가 매우 어렵고, 다형성은 문제를 해결하는 데 실패합니다. 당신의 예에서, Inarray 필요합니다 메소드의 동작이기 때문에 매개 변수의 유형을 확인하려면 의존합니다 이에. 다형성으로는 그렇게 할 수 없습니다. 즉,이 사건을 처리하기 위해 수업에 다형성 방법을 넣을 수는 없습니다. 그것은 당신의 matchcomparecriteria가 유형 매개 변수가 아닌 매개 변수의 행동.

사용하지 않는 규칙 instanceof 객체의 유형을 확인하여 행동 할 행동을 선택할 때 유효합니다. 분명히, 그 행동은 당신이 확인하는 다른 객체에 속합니다. 그러나이 경우의 행동 당신의 객체는 전달되는 객체의 유형에 따라 다르며 호출 객체에 속하는 객체에 속합니다. 이 사건은 당신이 재정의 할 때와 유사합니다 equals(). 통과 된 객체가 this 반대하고 동작을 구현하십시오. 테스트가 실패하면 False를 반환하십시오. 그렇지 않으면 평등 테스트를 수행하십시오.

결론 : 사용 instanceof 이 경우 괜찮습니다.

여기 더 길다 기사 스티브 예지 (Steve Yegge)는 간단하고 간단한 예를 사용하여 더 잘 설명합니다. 나는 이것이 당신의 문제에 큰 도움이된다고 생각합니다.

기억하다: 다형성은 그렇지 않은 경우를 제외하고는 좋습니다. :)

SmallTalk 접근법은 계층에 더 많은 층을 소개하는 것입니다. 그래서 ~ 사이 그리고 보다 큰 서브 클래스가 될 것입니다 Ranged CompareCriteria (또는 무언가), 그리고 rangecomparecritria :: matchcomparecritria 돌아올 것입니다 진실 그 자체의 두 인스턴스가 비슷한 지 물었을 때.

말하자면, 당신은 아마도 "matchcomparecriteria"의 이름을 조금 더 잘 표현하는 것으로 바꾸고 싶을 것입니다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top