수업에서 '최종'을 사용하는 것이 왜 그렇게 나쁜가?


34

PHP OOP 레거시 웹 사이트를 리팩토링하고 있습니다.

클래스에 '최종'을 사용하여 ''(을) 시작하려고합니다 make it explicit that the class is currently not extended by anything. 수업에 오면 많은 시간을 절약 할 수 있으며 protected속성이나 메서드의 이름을 바꾸거나 삭제하거나 수정할 수 있는지 궁금합니다 . 내가하면 정말 클래스를 확장 할 그냥하는 최종 키워드를 제거 할 수 있습니다 잠금을 해제 확장하는.

아이 클래스가없는 클래스에 오면 클래스를 최종으로 표시하여 해당 지식을 기록 할 수 있습니다. 다음에 내가 올 때 코드베이스에 자식이 있는지 확인하기 위해 코드베이스를 다시 검색하지 않아도됩니다. 따라서 리팩토링 동안 시간을 ​​절약 할 수 있습니다.

모든 것이 현명한 시간 절약 아이디어처럼 보입니다 .... 나는 종종 수업이 드문 / 특별한 경우에만 '최종'으로 이루어져야한다는 것을 읽었습니다.

어쩌면 모의 객체 생성을 망칠 수도 있고 내가 생각하지 않는 다른 부작용이있을 수도 있습니다.

내가 무엇을 놓치고 있습니까?


3
코드를 완전히 제어 할 수 있다면 끔찍하지는 않지만 OCD 측면에서는 약간의 생각입니다. 수업을 놓치면 어떻게됩니까 (예 : 자녀는 없지만 결석은 아닙니다)? 도구가 코드를 스캔하고 일부 클래스에 자식이 있는지 여부를 알려주는 것이 좋습니다. 이것을 라이브러리로 패키징하고 다른 사람에게 주 자마자 '최종'을 다루는 것은 고통이됩니다.
Job

예를 들어 MbUnit은 .Net 유닛 테스트를위한 개방형 프레임 워크이며 MsTest는 놀랍지 않습니다. 결과적으로 MSFT 방식으로 일부 테스트를 실행하려는 경우 5k를 MSFT로 셸해야합니다. 다른 테스트 실행자는 MSFT가 사용한 최종 클래스 때문에 MsTest로 빌드 된 테스트 dll을 실행할 수 없습니다.
Job

3
주제에 대한 일부 블로그 게시물 : Final Classes : 확장을위한 개방, 상속을 위해 폐쇄 됨 (2014 년 5 월; Mathias Verraes)
hakre

좋은 기사. 이것에 대한 내 생각을 말해줍니다. 그 주석에 대해 몰랐기 때문에 편리했습니다. 건배.
JW01

"PHP 5는 final 키워드를 도입하여 자식 클래스가 정의를 final로 접두어 메소드를 재정의하는 것을 방지합니다. 클래스 자체가 final로 정의되면 확장 할 수 없습니다." php.net/manual/en/language.oop5.final.php 전혀 나쁘지 않습니다.
블랙

답변:


54

나는 종종 수업이 드문 / 특별한 경우에만 '최종'으로 이루어져야한다는 것을 읽었습니다.

누가 쓴건 틀렸어 final자유롭게 사용하면 아무런 문제가 없습니다. 클래스가 상속을 염두에두고 설계되지 않았다는 것을 문서화하고 있으며 이는 기본적으로 모든 클래스에 적용 final됩니다. 많은주의가 필요합니다.

따라서 final기본적으로 사용 하는 것이 결코 나쁘지 않습니다. 사실, 많은 사람들은 이것이 기본값이되어야한다고 제안합니다 (예 : Jon Skeet) .

어쩌면 모의 객체 생성을 망칠 수도 있습니다 ...

이것은 실제로주의 사항이지만 수업을 조롱 해야하는 경우 항상 인터페이스를 사용할 수 있습니다. 이것은 조롱을 목적으로 모든 클래스를 상속에 공개하는 것보다 확실히 우수합니다.


1
1+ : 조롱을 조이기 때문에; 각 "최종"클래스에 대한 인터페이스 또는 추상 클래스 작성을 고려하십시오.
Spoike

글쎄, 그것은 스패너를 작품에 넣습니다. 이 늦은 도착은 다른 모든 답변과 모순됩니다. 이제 무엇을 믿어야할지 모르겠습니다. (나의 수락 된 답변을 선택 취소하고 재심사 중에 결정을
연기합니다

1
Java API 자체와 'final'키워드의 사용법을 찾는 빈도를 고려할 수 있습니다. 실제로는 자주 사용되지 않습니다. "가상"메소드가 호출 될 때 (Java에서 '최종'또는 '비공개'로 선언되지 않은 경우 모든 메소드가 가상 임) 또는 사용자 정의를 도입 할 때 동적 바인딩으로 인해 성능이 저하 될 수있는 경우에 사용됩니다. Java API 클래스의 서브 클래스는 'java.lang.String'서브 클래 싱과 같은 일관성 문제가 발생할 수 있습니다. Java 문자열은 정의당 값 개체이므로 나중에 값을 변경해서는 안됩니다. 서브 클래스는이 규칙을 어길 수 있습니다.
Jonny Dee

5
@Jonny 대부분의 Java API는 잘못 설계되었습니다. 대량의 제품은 10 년이 넘었으며 그 동안 많은 모범 사례가 개발되었음을 기억하십시오. 그러나 내 말을 듣지 마라. 자바 엔지니어들은 이것에 대해 상세하게 작성한 가장 먼저 Josh Bloch를 말한다 (예 : Effective Java) . Java API가 오늘날 개발되면 매우 다르게 보일 final것이며 훨씬 더 큰 역할을 할 것입니다.
Konrad Rudolph

1
'최종'을 더 자주 사용하는 것이 가장 좋은 방법이라고 확신하지는 않습니다. 필자의 의견으로는 '최종'은 실제로 성능 요구 사항이 지시하거나 서브 클래스에 의해 일관성이 손상되지 않도록 해야하는 경우에만 사용해야합니다. 다른 모든 경우에 필요한 문서는 특정 사용 패턴을 적용하는 키워드로 소스 코드가 아닌 문서 (어쨌든 작성해야 함)에 들어가야합니다. 나에게, 그것은 일종의 신을 재생합니다. 주석을 사용하는 것이 더 나은 솔루션입니다. 하나는 '@final'주석을 추가 할 수 있고 컴파일러는 경고를 발행 할 수 있습니다.
Jonny Dee

8

클래스에 하위 클래스가 없다는 메모를 남기고 싶다면 반드시 그렇게하고 주석을 사용하십시오. "최종"키워드는 주석이 아니며 언어 키워드를 사용하여 자신에게 무언가를 알리는 것 (그리고 그것이 의미하는 바를 아는 사람)은 나쁜 생각입니다.


17
이것은 완전히 거짓입니다! "언어 키워드를 사용하여 당신에게 무언가를 알리는 것은 […] 나쁜 생각입니다."– 반대로, 그것은 바로 언어 키워드입니다. 당신의 잠정적 경고는“그리고 그것이 무엇을 의미하는지 아는 것”은 물론 정확하지만 여기에는 적용되지 않습니다. OP가 final예상대로 사용 중입니다. 그것에 아무런 문제가 없습니다. 그리고 언어 기능을 사용하여 제약 조건을 적용하는 것이 항상 주석을 사용하는 것보다 우수합니다.
Konrad Rudolph

8
@Konrad : final"이 클래스의 하위 클래스를 만들면 안된다"(법적인 이유로 또는 다른 이유로) "이 클래스에는 현재 자식이 없으므로 보호 된 멤버를 엉망으로 만드는 것이 안전합니다"라는 표시를 제외 해야합니다. 의도는 final"자유롭게 편집 할 수있는"이라는 매우 반 추론이며 final클래스에는 protected멤버 가 없어야합니다 !
SF.

3
@ Konrad Rudolph 전혀 사소한 것이 아닙니다. 나중에 다른 사람들이 자신의 수업을 확장하려는 경우 "확장되지 않음"이라는 주석과 "확장 할 수 없음"이라는 키워드 사이에는 큰 차이가 있습니다.
Jeremy

2
@Konrad Rudolph OOP 언어 디자인에 대한 의문을 제기하는 것은 좋은 의견입니다. 그러나 우리는 PHP가 어떻게 작동하는지 알고 있으며, 봉인되지 않는 한 확장을 허용하는 다른 접근법을 취합니다. "그게 어떻게되어야합니까?"라는 말은 방어적인 것이기 때문에 키워드를 혼동하는 것이 가장 좋습니다.
Jeremy

3
@Jeremy 키워드를 혼동하지 않습니다. 키워드 final는 "이 클래스는 [현재] 확장되지 않아야합니다."라는 의미입니다. 여부 PHP가 마음에 이러한 철학으로 설계되었다 무관하다 : 그것은 final 결국, 키워드를. 둘째, 패치 워크와 전체적으로 나쁘게 PHP가 디자인 된 방식을 고려할 때 PHP의 디자인에 대한 논쟁은 실패 할 수밖에 없습니다.
Konrad Rudolph

5

"클래스를 마지막으로 선언 할 때" 에 대한 좋은 기사가 있습니다. 그것의 몇 가지 인용문 :

TL; DR : 클래스 final가 인터페이스를 구현하고 다른 공용 메소드가 정의되지 않은 경우 클래스를 항상 작성하십시오.

왜 사용해야 final합니까?

  1. 거대한 상속 체인 파괴 방지
  2. 격려 조성물
  3. 개발자가 사용자 공개 API에 대해 생각하도록 강요
  4. 개발자가 객체의 퍼블릭 API를 축소하도록 강요
  5. final클래스는 항상 확장 할 수
  6. extends 캡슐화를 끊다
  7. 유연성이 필요하지 않습니다
  8. 코드를 자유롭게 변경할 수 있습니다

피해야 할시기 final:

최종 수업은 다음과 같은 가정 하에서 만 효과적입니다.

  1. 최종 클래스가 구현하는 추상화 (인터페이스)가 있습니다
  2. 최종 클래스의 모든 공개 API는 해당 인터페이스의 일부입니다

이 두 가지 전제 조건 중 하나가 누락되면 코드가 실제로 추상화에 의존하지 않기 때문에 클래스를 확장 가능하게 만드는 시점에 도달 할 수 있습니다.

PS 훌륭한 독서를위한 @ocramius에게 감사합니다!


5

클래스의 "최종"은 다음을 의미합니다. 서브 클래스를 원하십니까? 계속해서 "최종", 원하는 서브 클래스를 삭제하십시오. 그래도 작동하지 않으면 나에게 불평하지 마십시오. 당신은 당신의 자신에있어.

클래스를 서브 클래 싱 할 수있는 경우 다른 클래스가 의존하는 동작은 서브 클래스가 따르는 추상적 인 용어로 설명해야합니다. 변동성을 기대하려면 발신자를 작성해야합니다. 문서는주의해서 작성해야합니다. 소스 코드가 아직 없기 때문에 사람들에게 "소스 코드를 보도록"말할 수 없습니다. 모든 노력입니다. 클래스가 서브 클래스 화 될 것으로 예상되지 않으면 불필요한 노력입니다. "최종"은 분명히이 노력이 이루어지지 않았으며 공정한 경고를 제공한다고 말합니다.


-1

당신이를 생각하지 않을 수 있습니다 것은 사실이다 ANY 가 가지고있는 클래스 수단의 변화가 새로운 QA 테스트를 받아야합니다.

당신이 정말로 의미하지 않는 한, 물건을 최종으로 표시하지 마십시오.


감사. 더 자세히 설명해 주시겠습니까? 클래스를 final(변경) 으로 표시하면 다시 테스트해야합니까?
JW01

4
나는 이것을 더 강력하게 말할 것이다. 클래스 디자인으로 인해 확장 기능을 사용할 수없는 경우를 제외하고는 최종 항목으로 표시하지 마십시오.
S.Lott

Thanks S.Lott-final의 나쁜 사용이 코드 / 프로젝트에 미치는 영향을 이해하려고합니다. 당신은 당신의 스페어 링 사용에 대해 너무 독단적으로 이어질 않은 나쁜 공포 이야기를 경험했다 final. 이 경험이 처음입니까?
JW01

1
@ JW01 : final클래스에는 하나의 주요 사용 사례가 있습니다. 하위 클래스가 다형성을 깰 수 있기 때문에 확장하지 않으려는 다형성 클래스가 있습니다. 서브 클래스 작성을 막지 않으면 사용 final하지 마십시오 . 그 외에는 쓸모가 없습니다.
S.Lott

JW01 @, 생산 환경에서 당신은 할 수 없습니다 허용 이 고객이 테스트와 인증 코드가 아니기 때문에, 최종를 제거 할 수 있습니다. 그러나 테스트를 위해 추가 코드를 추가 할 수는 있지만 수업을 연장 할 수 없기 때문에 원하는 것을 수행하지 못할 수도 있습니다.

-1

'최종'을 사용하면 코드를 사용하려는 다른 사람들의 자유가 사라집니다.

작성하는 코드가 귀하만을위한 것이며 공개 또는 고객에게 공개되지 않을 경우 물론 원하는 코드로 수행 할 수 있습니다. 그렇지 않으면 다른 사람이 코드를 작성하지 못하게됩니다. 종종 내 요구에 맞게 확장하기 쉬운 API로 작업해야했지만 '최종'에 의해 방해를 받았습니다.

또한 코드를 만들어서는 안되는 것이 private좋지만 protected. 물론 private"캡슐화"를 의미하고 구현 세부 사항으로 간주되는 것을 숨 깁니다. 그러나 API 프로그래머로서 메소드 xyz가 구현 세부 사항으로 간주되어 향후 버전에서 변경 / 삭제 될 수 있다는 사실을 문서화 할 수도 있습니다. 따라서 경고에도 불구하고 그러한 코드에 의존하는 모든 사람은 자신의 위험에 따라 코드를 작성합니다. 그러나 그는 실제로 그것을 수행하고 코드를 재사용하고 (솔직히 테스트를 거친) 솔루션을 더 빨리 만들 수 있습니다.

물론 API 구현이 오픈 소스 인 경우 '최종'을 제거하거나 메소드를 '보호'할 수 있지만 코드를 변경하고 패치 형태로 변경 사항을 추적해야합니다.

그러나 구현이 비공개 소스 인 경우 해결 방법을 찾거나 최악의 경우 사용자 지정 / 확장 가능성에 대한 제한이 적은 다른 API로 전환해야합니다.

'최종'이나 '비공개'가 악의적이라는 것을 알지 못하지만 프로그래머가 코드 재사용 및 확장 측면에서 코드를 생각하지 않았기 때문에 너무 자주 사용되는 것 같습니다.


2
"상속은 코드 재사용이 아닙니다".
quant_dev

2
좋아, 당신은 완벽한 정의를 주장한다면 당신이 맞습니다. 상속은 'is-a'관계를 표현하며 다형성을 허용하고 API를 확장하는 방법을 제공하는 사실입니다. 그러나 실제로 상속은 코드를 재사용하는 데 매우 자주 사용됩니다. 이것은 다중 상속의 경우 특히 그렇습니다. 그리고 슈퍼 클래스의 코드를 호출하자마자 실제로 코드를 재사용하고 있습니다.
Jonny Dee

@quant_dev : OOP에서의 재사용 성은 우선 모든 다형성을 의미합니다. 상속은 다형성 행동 (인터페이스 공유)의 중요한 포인트입니다.
팔콘

@ 팔콘 공유 인터페이스! = 공유 코드. 적어도 일반적인 의미는 아닙니다.
quant_dev

3
@quant_dev : OOP 의미에서 재사용 성이 잘못되었습니다. 인터페이스 공유 덕분에 단일 데이터 분석법이 많은 데이터 유형에서 작동 할 수 있습니다. 이것이 OOP 코드 재사용의 주요 부분입니다. 상속은 자동으로 인터페이스를 공유하여 코드 재사용 성을 크게 향상시킵니다. 이것이 OOP의 재사용성에 대해 이야기하는 이유입니다. 루틴을 사용하여 라이브러리를 작성하는 것은 프로그래밍 자체만큼이나 오래되었으며 거의 ​​모든 언어로 수행 할 수 있습니다. OOP에서의 코드 재사용은 그 이상입니다.
팔콘
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.