은은 "파생 된 개체"는 "기본 개체"의 교체로 사용할 수 있습니다.
것은의 당신의 기본 오브젝트는 방법이 있다고 가정 해 봅시다 : 여기
class BasicAdder
{
Anything Add(Number x, Number y);
}
// example of usage
adder = new BasicAdder
// elsewhere
Anything res = adder.Add(integer1, float2);
를, "번호는"숫자 같은 데이터 유형에 대한 기본 유형의 아이디어, 정수, 수레, 복식 등 같은 건입니다 즉 C++에 존재하지만, 여기에서는 특정 언어에 대해 논의하지 않습니다. 마찬가지로, 예를 들어, "Anything"은 모든 유형의 제한없는 값을 나타냅니다.
class ComplexAdder
{
Complex Add(Complex x, Complex y);
}
// example of usage
adder = new ComplexAdder
// elsewhere
Anything res = adder.Add(integer1, float2); // FAIL
따라서, 우리가 파산 LSP :
의이 복잡한 사용하는 "전문"입니다 파생 객체를 생각해 보자는 원래 개체에 대한 대체로서 사용할 수 없습니다, 받아 들일 수 없기 때문에 실제로 에 복합 매개 변수가 필요하기 때문에 integer1, float2
매개 변수가 필요합니다.
반면에 공변 반환 유형은 OK입니다. 반환 유형은 복소수로 복소수는 Anything
입니다.
이제
,의 다른 경우를 생각해 봅시다 : 기존의 객체를 사용하고 누구든지, 이제도에 아무런 변화 영향뿐만 아니라 새 개체를 사용할 수 있기 때문에
class SupersetComplexAdder
{
Anything Add(ComplexOrNumberOrShoes x, ComplexOrNumberOrShoes y);
}
// example of usage
adder = new SupersetComplexAdder
// elsewhere
Anything res = adder.Add(integer1, float2); // WIN
지금은 모든 것이 OK입니다 사용 시점.
물론 숫자와 관련하여 또는 일부 자동 유형 변환과 같은 "결합"또는 "수퍼 집합"유형을 항상 생성 할 수있는 것은 아닙니다. 그렇지만 특정 프로그래밍 언어에 대해 이야기하는 것이 아닙니다. 전반적인 아이디어가 중요합니다.
그것은 또한 당신이 반드시 클래스/메소드 서명 수준에서 LSP에 부합하는 것 같습니다
class SmartAdder
{
Anything Add(Anything x, Anything y)
{
if(x is not really Complex) throw error;
if(y is not really Complex) throw error;
return complex-add(x,y)
}
}
을 준수 또는 다양한 "수준"에서 LSP를 깰 수 있다는 것을 주목할 가치가있다. 그러나 그것은 무엇입니까? 종종 그렇지 않지만, 그것은 많은 것들에 달려 있습니다.
Contravariance 규칙이 데이터/프로 시저 추상화를 달성하는 데 도움이됩니다 어떻게?
나에게 분명하다. 당신이 말하는 만들 경우, 의미 구성 요소는 교체/스왑/교환 할 수 있습니다 :
- BASE : 송장의 계산 합 순진
- DER-1 : 병렬
- 에서 멀티 코어에 송장의 계산 합 DER-2 : 상세한 로깅
와 인보이스의 합을 계산 한 후, 새로 추가 invoi의
EUR 및 GBP 입력 값을 처리합니다. 예전 통화의 입력 값은 어떻습니까? 이를 생략하면 새 구성 요소 은이 아닌 오래된 구성 요소로 대체됩니다. 이전 구성 요소를 꺼내서 새 구성 요소를 꽂을 수 없으며 모든 것이 좋기를 바랍니다. 시스템의 다른 모든 것들은 USD 값을 입력으로 보낼 수 있습니다.
BASE에서 파생 된 새 구성 요소를 만들면 BASE가 이전에 필요했던 곳이면 어디서나 사용할 수 있다고 가정하는 것이 안전해야합니다. 어떤 장소가 BASE를 필요로하지만 DER-2가 사용 되었다면, 우리는 거기에 새로운 장소를 연결할 수 있어야합니다. 이것은 LSP입니다. 우리가 무언가가 깨진 수없는 경우
는
- 사용 did't 중 하나 장소는 BASE는하지만 더는
- 하거나 구성 요소가 는 BASE을지지 않습니다 (참고 필요한 실제로는-A가 필요 문구)
이제는 아무 것도 고장 나지 않으면 USD 또는 GBP 또는 단일 코어 또는 멀티 코어가 있는지 여부에 관계없이 하나를 취하여 다른 것으로 교체 할 수 있습니다. 이제 한 단계 위의 큰 그림을 보면서 더 이상 특정 유형의 통화를 신경 쓸 필요가 없다면 큰 그림을 더 쉽게 추상화하고 구성 요소를 내부적으로 처리해야합니다. 어쩐지.
그 데이터에 도움이 같은 하락하지 않는 경우/프로 시저 추상화 한 후 반대의 경우를 보면 : BASE에서 파생 된 구성 요소가 LSP을 준수하지 않은 경우 합법적으로 USDs의 값이 도착했을 때
, 다음은 오류를 발생 할 수 있습니다. 또는 더 나쁜 경우, 통지하지 않고 GBP로 처리 할 것입니다. 문제가있다.새로운 구성 요소를 수정하거나 (BASE의 모든 요구 사항을 준수하기 위해) 새이 규칙을 따르도록 다른 이웃 구성 요소를 변경해야합니다 (예 : EUR가 아닌 USD를 사용하거나 Adder가 예외를 throw 함). 큰 그림에 물건을 추가하여 작업하십시오. 즉, 구식 데이터를 감지하고 이전 구성 요소로 리디렉션하는 분기를 추가하십시오. 우리는 단지 이웃들에게 복잡성을 "누설했다"(그리고 아마도 우리는 SRP를 깨뜨릴 수밖에 없었다) 또는 "큰 그림"을 더 복잡하게 만들었다 (더 많은 어댑터, 조건, 브랜치, ..).
자세한 설명 주셔서 감사합니다. 그러나, Anything res = adder.Add (integer1, float2); // WIN' Add 메소드가'SupersetComplexAdder' 클래스의 인자로'Number'를 가지고 있다면 참일 수 있습니다. 'BasicAdder'가'Add' 메쏘드에서 Number 형이나 그 subtype을 인자로 기대하지 않는다는 것을 분명히 알았 기 때문에, 상속받은 클래스 내에서 supertype을 인자로 사용하면 호출자에게 특별한 기능이 없습니다. – Mac
하위 유형이 공변 인수를 허용하더라도이 경우 호출자 코드 (Client)는 'SupersetComplexAdder'객체를 다른 하위 유형 'BasicAdder'로 대체하는 조항을 잃어 버렸습니다. 이제 코드는 'SupersetComplexAdder '. 그리고 이것 자체가'BasicAdder'를위한 LSP를 깨뜨립니다. 나는 LSP가 여전히'SupersetComplexAdder'에 대해 사실 인 것으로 동의 할지라도. – Mac
답을 다시 읽은 후에 LSP에서 공분산을 지원하는 중요성에 대해 아주 명확한 그림을 얻었습니다. :) 다시 한번 감사드립니다. – Mac