개방형/폐쇄형 및 단일 책임 원칙

단일 책임
XNUMXD덴탈의 고체 객체 지향 디자인의 원칙은 변경하기 쉬운 코드 작성에 대한 좋은 지침을 제공하지만 일부 원칙의 경우 동기와 가치를 이해하기 어려울 수 있습니다. 개폐 특히 짜증난다: 소프트웨어 엔터티(클래스, 모듈, 기능 등)는 확장을 위해 열려야 하지만 수정을 위해 닫혀 있어야 합니다. 확장되었지만 수정되지 않았다는 것은 무엇을 의미합니까? 이 원칙은 본질적으로 깊고 복잡한 계급 계층으로 이어지는가? 가 있었다 일부 토론비판 최근에는 SOLID와 Open/Closed 원칙에 대해 설명했기 때문에 우리는 Open/Closed를 이해하고 이를 사용하여 동작을 쉽게 변경할 수 있는 클래스를 작성하는 Rescale 개발 팀의 경험을 공유해야 한다고 생각했습니다. 개발자가 최소한의 코드 수정으로 동작을 쉽게 변경할 수 있는 집중된 책임이 있는 클래스를 작성하도록 장려하기 때문에 우리는 개방형/폐쇄형을 단일 책임 원칙에 대한 보완책으로 봅니다.

설명

먼저, 몇 가지 초기 질문을 살펴보겠습니다. 코드가 확장된다는 것은 무엇을 의미합니까? 수정된다는게 무슨 뜻인가요? 코드는 수정 메서드에 조건을 추가하고, 추가 인수를 가져오고, 인수 속성에 따라 동작을 전환하는 등 코드 자체를 변경할 때. 이것은 기존 코드가 새로운 작업을 수행하도록 하는 방법에 대한 개발자의 첫 번째 생각인 경우가 많습니다. 다른 조건을 추가하기만 하면 됩니다. 코드는 extended 코드 자체를 수정하지 않고 동작을 변경할 때 – 다른 협력자를 주입. 우리 코드가 이러한 확장을 수용할 수 있으려면 달성하려는 작업의 각 측면에 대해 서로 다른 개체를 주입하는 다른 많은 SOLID 원칙을 따라야 합니다. 이를 위해서는 작업의 각 측면이 서로 다른 개체에 의해 수행되어야 하며, 이는 단일 책임 원칙의 핵심입니다. 개체는 한 가지 작업만 수행해야 합니다. 개방형/폐쇄형은 개발자가 책임을 분산하는 코드를 작성하도록 장려하고 긴 메서드와 대규모 클래스를 늘리지 않고도 동작을 쉽게 변경할 수 있다는 이점을 제공합니다.

예제

예를 들어 이 모든 이론을 설명해 보겠습니다. Rescale에서는 최근 많은 코드를 리팩토링했습니다. REST API 클라이언트를 사용합니다. API 클라이언트는 호출자가 원하는 각 유형의 요청에 대해 서로 다른 방법으로 작성되는 경우가 많으며 이것이 우리의 시작 방식입니다. 다음과 같은 인터페이스가 있었습니다.

공용 인터페이스 APIClient { 분석 getAnalytic(long jobId); HardwareSummary getHardwareSummary(long jobId); ... }

각 메소드 구현은 다음과 같습니다.

공개 분석 getAnalytic(long jobId) { 문자열 경로 = “/api/jobs/” + jobId + “/analytic/”; 문자열 응답 = makeHttpRequest(new URL(this.baseApiUrl, path)); return parJson(응답, Analysis.class); }

이것은 함께 일하는 고통이었습니다. API에서 새로운 데이터를 얻고 싶을 때마다 새롭고 중복되는 메서드를 추가해야 했습니다. 이 고객은 그렇지 않았습니다. 연장을 위해 열려있습니다, 동작을 변경하려면 클래스를 수정해야 했습니다. 그것은 책임이 모호한 데서 비롯되었습니다. 위의 방법은 간단해 보이지만 실제로는 여러 가지 다른 책임과 그에 상응하는 지식이 있습니다. 각 요청 유형에 대한 경로 형식을 지정하는 방법을 알고 있습니다. API에 http 요청을 보내는 방법을 알고 있으며 각 요청에 대해 json을 구문 분석하는 방법을 알고 있습니다. 우리는 API 클라이언트에 단 하나의 책임 있는 요청만 제공하기 위해 이를 리팩터링하기로 결정했습니다. 대신, 다른 책임을 대신하는 Request 객체를 전달하여 이를 확장합니다. 이제 단 하나의 메소드를 갖춘 API 클라이언트 인터페이스가 생겼습니다.

공개 인터페이스 APIClient { 공개 T get(요청 요청); }

각 요청 유형은 상대적으로 정적이므로 요청 개체를 생성하는 정적 팩토리 메서드가 있습니다.

공개 클래스 요청 { 공개 정적 무효 분석 요청(작업) { ... } }

그리고 Java 제네릭 덕분에 호출자는 올바른 유형의 객체를 돌려받습니다. 이제 다음과 같이 자연스럽게 보이는 코드가 생겼습니다.

분석 분석 = client.get(Request.forAnalytic(this.job));

그리고 API에서 새로운 정보를 검색하는 것도 쉽습니다. API 클라이언트를 수정할 필요가 없으며 다른 요청을 전달하여 확장하기만 하면 됩니다.

요약

개방형/폐쇄형이 의미하는 바에 대해 많은 혼란이 있지만, 이는 단순히 개체가 책임을 집중하고 주입된 다른 개체와 상호 작용해야 한다는 것입니다. 이렇게 하면 개발자가 자유롭게 다른 협력자를 주입하여 동작을 변경할 수 있습니다. 대규모 코드베이스에서 작업해 본 사람이라면 누구나 Open/Closed를 염두에 두지 않고 개발된 섹션을 본 적이 있을 것입니다. 이 코드는 표면적으로 단순하며 "일을 완료합니다". 문제는 기업이 원하는 변화는 필연적으로 변하기 때문에 직업을 바꾸는 유일한 방법은 코드를 바꾸는 것뿐이라는 점이다. 메서드는 조건문과 스위치 문을 축적하고, 클래스는 필드를 축적하며, 코드는 한눈에 이해하기 어려워집니다. 작업을 수행하는 가장 쉬운 방법은 단순히 메서드에 몇 줄을 더 추가하는 것이기 때문에 잘못된 디자인은 그 자체로 문제가 됩니다. 개발자가 개방형/폐쇄형을 염두에 둔다면 확장 가능한 동작을 갖춘 객체를 생성할 수 있는 기회를 포착하고 개발 비용이 통제할 수 없을 정도로 늘어나는 것을 방지할 수 있을 것입니다.

저자

  • 애덤 매켄지

    CTO로서 Adam은 HPC 및 고객 성공 팀을 관리하는 책임을 맡고 있습니다. Adam은 Boeing에서 경력을 시작하여 787년 동안 XNUMX을 작업하면서 구조 및 소프트웨어 엔지니어링 프로젝트를 관리하고 날개를 설계, 분석 및 최적화했습니다. Adam은 오레곤 주립대학교에서 우등으로 기계공학 학사학위를 취득했습니다.

비슷한 게시물