우리는 일상적인 개발에서 종종 몇 가지 원칙과 패턴을 따라야 합니다. 이것은 실제로 우리가 어떤 소프트웨어를 개발하든 우리에게 유익하고 무해할 것입니다. 이 기사는 이러한 원칙을 요약하고 설명의 의미를 설명하여 모든 사람에게 참고 가치를 제공하고 Java 지식을 더 잘 배우는 데 도움이 되기를 바랍니다. 아파치 php mysql
시작하세요!
객체 지향의 기본 원칙(고체)은 5가지인데, 자주 언급되는 이 5가지 외에도 데메테르의 법칙과 구성 및 재사용의 원칙 등이 있습니다. , 그래서 일반적인 기사에는 글쓰기에 대한 6~7가지 원칙이 있습니다. 또한 다른 관련 책이나 인터넷에 나타나는 몇 가지 원칙도 제공하겠습니다.
원칙, 클래스는 한 가지만 수행하는 것이 가장 좋으며, 한 가지만 변경하면 됩니다. 단일 책임 원칙은 낮은 결합도와 높은 응집도라는 객체 지향 원칙의 확장으로 볼 수 있습니다. 책임은 응집력을 향상시키고 변화의 원인을 줄이기 위한 변화의 원인으로 정의됩니다.
정의
객체에는 단일 책임만 포함되어야 하며 책임은 클래스에 완전히 캡슐화되어야 합니다. (모든 객체는 하나의 책임을 가져야 하며, 그 책임은 클래스에 의해 완전히 캡슐화되어야 합니다.) 즉, 클래스가 변경되는 이유는 단 하나뿐이라고 정의됩니다. 고가용성 아키텍처 설계를 위한 9가지 솔루션에 대한 자세한 설명을 보려면 여기를 클릭하세요.
원리 분석
클래스(또는 모듈만큼 크거나 메소드만큼 작음)가 더 많은 책임을 질수록 재사용할 가능성이 낮아지고, 클래스가 너무 많은 책임을 맡는 경우에는 동일합니다. 이러한 책임은 서로 결합되어 있으며, 책임 중 하나가 변경되면 다른 책임의 운영에 영향을 미칠 수 있습니다.
클래스의 책임에는 주로 데이터 책임과 행동 책임이라는 두 가지 측면이 포함됩니다. 데이터 책임은 속성을 통해 반영되고, 행동 책임은 메서드를 통해 반영됩니다.
단일 책임 원칙은 높은 응집력과 낮은 결합도를 달성하기 위한 지침입니다. 이는 많은 코드 리팩토링 기술에서 찾을 수 있습니다. 이는 가장 간단하지만 적용하기 가장 어려운 원칙입니다. 다양한 책임과 분리가 필요합니다. 그리고 클래스의 여러 책임을 발견하려면 디자이너에게 강력한 분석 및 디자인 기능과 관련 리팩토링 경험이 필요합니다.
장점
수업의 복잡성을 줄이고, 수업의 책임이 명확하고 명확합니다. 예를 들어 데이터 책임과 행동 책임은 명확하고 명확합니다.
클래스의 가독성과 유지 관리성을 향상시키고,
변경으로 인한 위험을 줄이고, 변경은 필수적이며, 인터페이스의 단일 책임이 잘 수행되면 인터페이스 수정은 해당 클래스에만 영향을 미치며, 변경이 필요하지 않습니다. 이는 시스템의 확장성과 유지 관리에 매우 도움이 되는 다른 인터페이스에 영향을 줍니다.
참고: 단일 책임 원칙은 인터페이스나 클래스 디자인이 합리적인지 여부를 측정하기 위해 "책임" 또는 "변경 이유"를 사용하여 프로그램 작성 표준을 제안하지만 "책임"과 "변경 이유"는 특정 표준이 아닌 경우 클래스는 어떤 책임을 담당해야 합니까? 이러한 책임은 어떻게 자세히 설명되어 있나요? 개선 후에는 인터페이스나 클래스가 있나요? 이는 실제 상황에 따라 고려되어야 합니다. 프로젝트마다, 환경마다 다릅니다.
Example
SpringMVC에서 Entity, DAO, Service, Controller, Util 등의 분리.
Open - ClosedPrinciple,OCP, 확장을 위해 개방, 수정을 위해 폐쇄(디자인 패턴의 핵심 원칙)
Definition
소프트웨어 엔터티(예: 클래스, 모듈 및 함수) ) 확장을 위해 열려 있어야 하고 수정을 위해 닫혀 있어야 합니다. 이는 시스템이나 모듈이 확장에는 개방되어 있고 수정에는 폐쇄되어 있음을 의미합니다. 좋은 시스템은 소스 코드를 수정하지 않고도 기능을 확장할 수 있습니다. 열림과 닫힘의 원리를 구현하는 열쇠는 추상화이다.
원리 분석
소프트웨어 엔터티가 필요에 따라 변경되면 기존 소프트웨어를 변경하는 것보다 기존 소프트웨어 엔터티를 확장하여 소프트웨어의 새로운 요구 사항을 충족하는 새로운 동작을 제공하도록 노력하세요. 적응성과 유연성의 정도. 기존 소프트웨어 모듈, 특히 가장 중요한 추상화 계층 모듈은 수정할 수 없으므로 변화하는 소프트웨어 시스템에 어느 정도의 안정성과 연속성을 제공합니다.
개방-폐쇄 원칙을 실현하는 핵심은 추상화입니다. "개방-폐쇄" 원칙에서 수정이 허용되지 않는 것은 추상 클래스나 인터페이스이고, 확장이 허용되는 것은 구체적인 구현 클래스입니다. 추상 클래스와 인터페이스는 "개방-폐쇄" 원칙에 있습니다. 즉, 가능한 변화하는 요구 사항을 예측하고 가능한 모든 알려진 확장을 예측하는 "-"가 매우 중요한 역할을 합니다.
여기가 핵심이에요!가동성의 폐쇄 원리: 시스템의 가변 요소를 찾아서 캡슐화합니다. 이는 "개방-폐쇄" 원칙을 가장 잘 구현한 것입니다. 프로그램의 가변 요소를 포함해야 하며 함께 사용하는 가변 요소를 포함하지 않도록 주의하십시오. 가장 좋은 해결책은 크기가 너무 큰 클래스, 매우 긴 클래스의 출현을 피하는 것입니다. 그리고 매우 긴 방법으로 프로그램에 예술적 풍미를 더하고 프로그램을 예술적으로 만드는 것이 우리의 목표입니다!
Example
디자인 모드에서는 템플릿 방법 모드와 관찰자 모드가 모두 활성화됩니다. 폐쇄의 원칙. 고가용성 아키텍처 설계를 위한 9가지 솔루션에 대한 자세한 설명을 보려면 여기를 클릭하세요.
Liskov 대체 원리, LSP: 기본 클래스가 나타날 수 있는 모든 곳에 하위 클래스도 나타날 수 있습니다. 이 아이디어는 상속 메커니즘에 대한 제약 사양으로 표현되며 하위 클래스만 대체될 수 있습니다. 기본 클래스가 사용되는 경우에만 시스템은 런타임 중에 하위 클래스를 식별할 수 있으며 이는 상속 재사용을 보장하는 기반입니다.
정의
첫 번째 정의 방법은 상대적으로 엄격합니다. S 유형의 모든 객체 o1에 대해 T 유형의 객체 o2가 있으므로 T로 정의된 모든 프로그램 P가 모든 객체 o1에서 대체됩니다. o2, 프로그램 P의 동작이 변경되지 않으면 S 유형은 T 유형의 하위 유형입니다.
두 번째, 이해하기 쉬운 정의: 기본 클래스(상위 클래스)를 참조하는 모든 위치는 해당 하위 클래스의 개체를 투명하게 사용할 수 있어야 합니다. 즉, 하위 클래스는 그것이 나타나는 위치에서 기본 클래스를 대체할 수 있어야 합니다. 하위 클래스는 기본 클래스를 기반으로 새로운 동작을 추가할 수도 있습니다.
(리스코프 대체 원리는 2008년 튜링상 수상자 바바라 리스코프, 미국 최초의 컴퓨터 과학 박사이자 MIT 교수, 카네기멜론 대학교 자넷 윙 교수가 1994년에 제안한 것입니다. 원문은 다음과 같습니다. 다음과 같이 :q(x)가 T 유형의 객체 x에 대해 증명 가능한 속성이라고 가정합니다. 그러면 q(y)는 S 유형의 객체 y에 대해 참이어야 합니다. 여기서 S는 T의 하위 유형입니다. )
원리 분석
이 말하는 것입니다. 기본 정보 클래스와 하위 클래스 간의 관계는 이 관계가 존재할 때만 Liskov 대체 원칙이 존재합니다. 정사각형은 직사각형이다 리스코프 대체 원리를 이해하는 전형적인 예입니다.
리스코프 대체 원칙은 대중적인 방식으로 표현될 수 있습니다. 소프트웨어에서 기본 클래스 개체를 사용할 수 있다면 해당 하위 클래스 개체도 사용할 수 있어야 합니다. 기본 클래스가 하위 클래스로 대체되면 프로그램은 오류나 예외를 생성하지 않습니다. 소프트웨어 엔터티가 하위 클래스를 사용하는 경우에는 기본 클래스를 사용하지 못할 수도 있습니다.
리스코프 대체 원칙은 열기 및 닫기 원칙을 구현하는 중요한 방법 중 하나입니다. 하위 클래스 개체는 기본 클래스 개체가 사용되는 모든 곳에서 사용할 수 있으므로 기본 클래스 유형을 사용하여 프로그램에서 개체를 정의하고 결정합니다. 런타임 시 해당 하위 클래스 유형을 선택하고 상위 클래스 객체를 하위 클래스 객체로 바꿉니다.
(인터페이스 분리 원칙, ISL): 클라이언트는 필요하지 않은 인터페이스에 의존해서는 안 됩니다. (이 법칙은 데메테르의 법칙과 일치합니다)
정의
클라이언트는 필요하지 않은 인터페이스에 의존해서는 안 됩니다.
또 다른 정의 방법: 인터페이스가 너무 크면 더 작은 인터페이스로 분할해야 합니다. 이 인터페이스를 사용하는 클라이언트는 관련 방법만 알면 됩니다.
이 정의의 인터페이스는 정의된 메서드를 나타냅니다. 예를 들어, 외부에서 클래스의 공개 메서드를 호출합니다. 이 방법은 외부 세계에 대한 인터페이스입니다.
원리 분석
1) 인터페이스 격리의 원칙은 하나의 전체 인터페이스를 사용하는 대신 여러 개의 특화된 인터페이스를 사용하는 것을 의미합니다. 각 인터페이스는 상대적으로 독립적인 역할을 맡아야 하며, 해서는 안 되는 일을 해서는 안 되지만, 해야 할 모든 일을 해야 합니다.
인터페이스는 하나의 역할만을 나타내며, 각 역할에는 고유한 특정 인터페이스가 있습니다. 이 원칙을 "역할 격리 원칙"이라고 부를 수 있습니다.
인터페이스는 클라이언트가 필요로 하는 동작, 즉 필수 메서드만 제공합니다. 클라이언트가 필요로 하지 않는 동작은 숨겨지므로 클라이언트에는 큰 인터페이스 대신 가능한 한 작은 별도의 인터페이스를 제공해야 합니다. 전체 인터페이스.
2) 인터페이스 격리 원칙을 사용하여 인터페이스를 분할하는 경우 먼저 단일 책임 원칙을 충족하고 인터페이스에서 관련 작업 집합을 정의해야 하며, 높은 응집력을 충족한다는 전제 하에 인터페이스가 더 좋습니다.
3) 시스템을 설계할 때 맞춤형 서비스를 사용할 수 있습니다. 즉, 클라이언트마다 서로 다른 너비와 너비의 인터페이스를 제공하고, 사용자에게 필요한 동작만 제공하고, 사용자에게 필요하지 않은 동작은 숨기는 것입니다.
종속성 반전 원칙은 특정 구현이 아닌 추상화에 의존합니다. 특히 상위 모듈은 하위 모듈에 의존하지 않습니다. 추상화는 구체적에 의존하지 않고, 구체적은 추상화에 의존합니다.
Definition
상위 수준 모듈은 하위 수준 모듈에 의존해서는 안 되며, 모두 추상화에 의존해야 합니다. 추상화는 세부 사항에 의존해서는 안 되며, 세부 사항은 추상화에 의존해야 합니다. 간단히 말해서, 종속성 반전 원칙은 클라이언트가 추상 결합에 의존하도록 요구합니다. 원리 표현:
1) 추상화는 세부 사항에 의존해서는 안 됩니다. 세부 사항은 추상화에 의존해야 합니다.
2) 프로그래밍은 구현을 위한 것이 아니라 인터페이스를 위한 것입니다.
원리 분석
1) 열고 닫는 원리가 객체지향 설계의 목표라면, 종속성 역전 원리는 객체지향 설계의 "열림과 닫힘" 원리를 달성하기 위한 수단입니다. 최상의 "열기 및 닫기" 원칙을 달성하려면 종속성 반전 원칙을 최대한 준수해야 합니다. 종속성 역전 원칙은 "추상화"에 대한 최고의 사양이라고 할 수 있습니다! 나는 개인적으로 의존역전의 원리가 리히터 대체원리의 보완이라고도 생각한다. Liskov 대체 원칙을 이해하면 종속성 역전 원칙도 쉽게 이해할 수 있습니다.
2) 종속성 반전 원칙을 구현하는 일반적인 방법 중 하나는 코드에서 추상 클래스를 사용하고 구성 파일에 구체적인 클래스를 넣는 것입니다.
3) 클래스 간 결합: 제로 결합 관계, 구체적 결합 관계, 추상 결합 관계. 종속성 역전 원칙은 클라이언트가 추상적인 방식으로 결합하는 것에 의존하도록 요구합니다. 이는 종속성 역전 원칙의 핵심입니다.
예
이 종속성 반전을 이해하려면 먼저 객체 지향 설계의 종속성 개념을 이해해야 합니다.
Dependency(종속성): 특정 항목을 변경하면 사용하는 다른 항목에 영향을 줄 수 있는 사용 관계입니다. Things, dependency는 한 가지가 다른 것을 사용한다는 것을 나타내야 할 때 사용됩니다. (A 클래스의 변경으로 인해 B 클래스가 변경된다고 가정하면 B 클래스는 A 클래스에 종속된다고 합니다.) 대부분의 경우 다른 클래스의 객체를 매개변수로 사용하는 특정 클래스의 메서드에는 종속 관계가 반영됩니다. . UML에서 종속 관계는 종속 당사자에서 종속 당사자를 가리키는 화살표가 있는 점선으로 표시됩니다.
예: 특정 시스템은 다양한 데이터 소스의 데이터를 데이터베이스의 데이터(DatabaseSource) 또는 텍스트 파일의 데이터(TextSource)와 같은 여러 형식으로 변환할 수 있는 데이터 변환 모듈을 제공합니다. 파일(XMLTransformer), XLS 파일(XLSTransformer) 등
요구 사항 변경으로 인해 시스템에 새로운 데이터 소스나 새로운 파일 형식이 추가될 때마다 클라이언트 클래스 MainClass의 소스 코드가 추가됩니다. , 새 클래스를 사용하려면 수정이 필요하지만 열기 및 닫기 원칙을 위반합니다. 이제 종속성 반전 원칙을 사용하여 리팩터링되었습니다. 고가용성 아키텍처 설계를 위한 9가지 솔루션에 대한 자세한 설명을 보려면 여기를 클릭하세요.
물론 특정 상황에 따라 AbstractSource를 AbstractStransformer에 주입할 수도 있습니다. 종속성 주입에는 세 가지 방법이 있습니다:
<ol class="hljs-ln list-paddingleft-2"><li><p class="hljs-ln-line"><span class="hljs-comment"><span class="hljs-comment">/** </span></span></p></li><li><p class="hljs-ln-numbers"><span style="font-family: "Microsoft Yahei", "Hiragino Sans GB", Helvetica, "Helvetica Neue", 微软雅黑, Tahoma, Arial, sans-serif;"> * 依赖注入是依赖AbstractSource抽象注入的,而不是具体 </span><br/></p></li><li><p class="hljs-ln-numbers"><span style="font-family: "Microsoft Yahei", "Hiragino Sans GB", Helvetica, "Helvetica Neue", 微软雅黑, Tahoma, Arial, sans-serif;">* DatabaseSource </span><br/></p></li><li><p class="hljs-ln-numbers"><span style="font-family: "Microsoft Yahei", "Hiragino Sans GB", Helvetica, "Helvetica Neue", 微软雅黑, Tahoma, Arial, sans-serif;">* </span><br/></p></li><li><p class="hljs-ln-numbers"><span class="hljs-comment" style="font-family: "Microsoft Yahei", "Hiragino Sans GB", Helvetica, "Helvetica Neue", 微软雅黑, Tahoma, Arial, sans-serif;"> */</span><span style="font-family: "Microsoft Yahei", "Hiragino Sans GB", Helvetica, "Helvetica Neue", 微软雅黑, Tahoma, Arial, sans-serif;"> </span><br/></p></li><li><p class="hljs-ln-numbers"><span class="hljs-keyword" style="font-family: "Microsoft Yahei", "Hiragino Sans GB", Helvetica, "Helvetica Neue", 微软雅黑, Tahoma, Arial, sans-serif;">abstract</span><span style="font-family: "Microsoft Yahei", "Hiragino Sans GB", Helvetica, "Helvetica Neue", 微软雅黑, Tahoma, Arial, sans-serif;"> </span><span class="hljs-class" style="font-family: "Microsoft Yahei", "Hiragino Sans GB", Helvetica, "Helvetica Neue", 微软雅黑, Tahoma, Arial, sans-serif;"><span class="hljs-keyword">class</span> <span class="hljs-title">AbstractStransformer</span> </span><span style="font-family: "Microsoft Yahei", "Hiragino Sans GB", Helvetica, "Helvetica Neue", 微软雅黑, Tahoma, Arial, sans-serif;">{ </span><br/></p></li><li><p class="hljs-ln-numbers"><span style="font-family: "Microsoft Yahei", "Hiragino Sans GB", Helvetica, "Helvetica Neue", 微软雅黑, Tahoma, Arial, sans-serif;"> </span><span class="hljs-keyword" style="font-family: "Microsoft Yahei", "Hiragino Sans GB", Helvetica, "Helvetica Neue", 微软雅黑, Tahoma, Arial, sans-serif;">private</span><span style="font-family: "Microsoft Yahei", "Hiragino Sans GB", Helvetica, "Helvetica Neue", 微软雅黑, Tahoma, Arial, sans-serif;"> AbstractSource source; </span><br/></p></li><li><p class="hljs-ln-numbers"><span style="font-family: "Microsoft Yahei", "Hiragino Sans GB", Helvetica, "Helvetica Neue", 微软雅黑, Tahoma, Arial, sans-serif;"> </span><span class="hljs-comment" style="font-family: "Microsoft Yahei", "Hiragino Sans GB", Helvetica, "Helvetica Neue", 微软雅黑, Tahoma, Arial, sans-serif;"><span class="hljs-comment">/** </span></span><br/></p></li><li><p class="hljs-ln-numbers"><span style="font-family: "Microsoft Yahei", "Hiragino Sans GB", Helvetica, "Helvetica Neue", 微软雅黑, Tahoma, Arial, sans-serif;"> * 构造注入(Constructor Injection):通过构造函数注入实例变量。 </span><br/></p></li><li><p class="hljs-ln-numbers"><span class="hljs-comment" style="font-family: "Microsoft Yahei", "Hiragino Sans GB", Helvetica, "Helvetica Neue", 微软雅黑, Tahoma, Arial, sans-serif;"> */</span><span style="font-family: "Microsoft Yahei", "Hiragino Sans GB", Helvetica, "Helvetica Neue", 微软雅黑, Tahoma, Arial, sans-serif;"> </span><br/></p></li><li><p class="hljs-ln-numbers"><span style="font-family: "Microsoft Yahei", "Hiragino Sans GB", Helvetica, "Helvetica Neue", 微软雅黑, Tahoma, Arial, sans-serif;"> </span><span class="hljs-function" style="font-family: "Microsoft Yahei", "Hiragino Sans GB", Helvetica, "Helvetica Neue", 微软雅黑, Tahoma, Arial, sans-serif;"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">AbstractStransformer</span><span class="hljs-params">(AbstractSource source)</span></span><span style="font-family: "Microsoft Yahei", "Hiragino Sans GB", Helvetica, "Helvetica Neue", 微软雅黑, Tahoma, Arial, sans-serif;">{ </span><br/></p></li><li><p class="hljs-ln-numbers"><span style="font-family: "Microsoft Yahei", "Hiragino Sans GB", Helvetica, "Helvetica Neue", 微软雅黑, Tahoma, Arial, sans-serif;"> </span><span class="hljs-keyword" style="font-family: "Microsoft Yahei", "Hiragino Sans GB", Helvetica, "Helvetica Neue", 微软雅黑, Tahoma, Arial, sans-serif;">this</span><span style="font-family: "Microsoft Yahei", "Hiragino Sans GB", Helvetica, "Helvetica Neue", 微软雅黑, Tahoma, Arial, sans-serif;">.source = source; </span><br/></p></li><li><p class="hljs-ln-numbers"><span style="font-family: "Microsoft Yahei", "Hiragino Sans GB", Helvetica, "Helvetica Neue", 微软雅黑, Tahoma, Arial, sans-serif;"> } </span><br/></p></li><li><p class="hljs-ln-numbers"><span style="font-family: "Microsoft Yahei", "Hiragino Sans GB", Helvetica, "Helvetica Neue", 微软雅黑, Tahoma, Arial, sans-serif;"> </span><span class="hljs-comment" style="font-family: "Microsoft Yahei", "Hiragino Sans GB", Helvetica, "Helvetica Neue", 微软雅黑, Tahoma, Arial, sans-serif;"><span class="hljs-comment">/** </span></span><br/></p></li><li><p class="hljs-ln-numbers"><span style="font-family: "Microsoft Yahei", "Hiragino Sans GB", Helvetica, "Helvetica Neue", 微软雅黑, Tahoma, Arial, sans-serif;"> * 设值注入(Setter Injection):通过Setter方法注入实例变量。 </span><br/></p></li><li><p class="hljs-ln-numbers"><span style="font-family: "Microsoft Yahei", "Hiragino Sans GB", Helvetica, "Helvetica Neue", 微软雅黑, Tahoma, Arial, sans-serif;"> * </span><span class="hljs-doctag" style="font-family: "Microsoft Yahei", "Hiragino Sans GB", Helvetica, "Helvetica Neue", 微软雅黑, Tahoma, Arial, sans-serif;">@param</span><span style="font-family: "Microsoft Yahei", "Hiragino Sans GB", Helvetica, "Helvetica Neue", 微软雅黑, Tahoma, Arial, sans-serif;"> source : the sourceto set </span><br/></p></li><li><p class="hljs-ln-numbers"><span class="hljs-comment" style="font-family: "Microsoft Yahei", "Hiragino Sans GB", Helvetica, "Helvetica Neue", 微软雅黑, Tahoma, Arial, sans-serif;"> */</span><span style="font-family: "Microsoft Yahei", "Hiragino Sans GB", Helvetica, "Helvetica Neue", 微软雅黑, Tahoma, Arial, sans-serif;"> </span><br/></p></li><li><p class="hljs-ln-numbers"><span style="font-family: "Microsoft Yahei", "Hiragino Sans GB", Helvetica, "Helvetica Neue", 微软雅黑, Tahoma, Arial, sans-serif;"> </span><span class="hljs-function" style="font-family: "Microsoft Yahei", "Hiragino Sans GB", Helvetica, "Helvetica Neue", 微软雅黑, Tahoma, Arial, sans-serif;"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">setSource</span><span class="hljs-params">(AbstractSource source)</span> </span><span style="font-family: "Microsoft Yahei", "Hiragino Sans GB", Helvetica, "Helvetica Neue", 微软雅黑, Tahoma, Arial, sans-serif;">{ </span><br/></p></li><li><p class="hljs-ln-numbers"><span style="font-family: "Microsoft Yahei", "Hiragino Sans GB", Helvetica, "Helvetica Neue", 微软雅黑, Tahoma, Arial, sans-serif;"> </span><span class="hljs-keyword" style="font-family: "Microsoft Yahei", "Hiragino Sans GB", Helvetica, "Helvetica Neue", 微软雅黑, Tahoma, Arial, sans-serif;">this</span><span style="font-family: "Microsoft Yahei", "Hiragino Sans GB", Helvetica, "Helvetica Neue", 微软雅黑, Tahoma, Arial, sans-serif;">.source = source; </span><br/></p></li><li><p class="hljs-ln-numbers"><span style="font-family: "Microsoft Yahei", "Hiragino Sans GB", Helvetica, "Helvetica Neue", 微软雅黑, Tahoma, Arial, sans-serif;"> } </span><br/></p></li><li><p class="hljs-ln-numbers"><span style="font-family: "Microsoft Yahei", "Hiragino Sans GB", Helvetica, "Helvetica Neue", 微软雅黑, Tahoma, Arial, sans-serif;"> </span><span class="hljs-comment" style="font-family: "Microsoft Yahei", "Hiragino Sans GB", Helvetica, "Helvetica Neue", 微软雅黑, Tahoma, Arial, sans-serif;"><span class="hljs-comment">/** </span></span><br/></p></li><li><p class="hljs-ln-numbers"><span style="font-family: "Microsoft Yahei", "Hiragino Sans GB", Helvetica, "Helvetica Neue", 微软雅黑, Tahoma, Arial, sans-serif;"> * 接口注入(Interface Injection):通过接口方法注入实例变量。 </span><br/></p></li><li><p class="hljs-ln-numbers"><span style="font-family: "Microsoft Yahei", "Hiragino Sans GB", Helvetica, "Helvetica Neue", 微软雅黑, Tahoma, Arial, sans-serif;"> * </span><span class="hljs-doctag" style="font-family: "Microsoft Yahei", "Hiragino Sans GB", Helvetica, "Helvetica Neue", 微软雅黑, Tahoma, Arial, sans-serif;">@param</span><span style="font-family: "Microsoft Yahei", "Hiragino Sans GB", Helvetica, "Helvetica Neue", 微软雅黑, Tahoma, Arial, sans-serif;"> source </span><br/></p></li><li><p class="hljs-ln-numbers"><span class="hljs-comment" style="font-family: "Microsoft Yahei", "Hiragino Sans GB", Helvetica, "Helvetica Neue", 微软雅黑, Tahoma, Arial, sans-serif;"> */</span><span style="font-family: "Microsoft Yahei", "Hiragino Sans GB", Helvetica, "Helvetica Neue", 微软雅黑, Tahoma, Arial, sans-serif;"> </span><br/></p></li><li><p class="hljs-ln-numbers"><span style="font-family: "Microsoft Yahei", "Hiragino Sans GB", Helvetica, "Helvetica Neue", 微软雅黑, Tahoma, Arial, sans-serif;"> </span><span class="hljs-function" style="font-family: "Microsoft Yahei", "Hiragino Sans GB", Helvetica, "Helvetica Neue", 微软雅黑, Tahoma, Arial, sans-serif;"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">transform</span><span class="hljs-params">(AbstractSource source )</span> </span><span style="font-family: "Microsoft Yahei", "Hiragino Sans GB", Helvetica, "Helvetica Neue", 微软雅黑, Tahoma, Arial, sans-serif;">{ </span><br/></p></li><li><p class="hljs-ln-numbers"><span style="font-family: "Microsoft Yahei", "Hiragino Sans GB", Helvetica, "Helvetica Neue", 微软雅黑, Tahoma, Arial, sans-serif;"> source.getSource(); </span><br/></p></li><li><p class="hljs-ln-numbers"><span style="font-family: "Microsoft Yahei", "Hiragino Sans GB", Helvetica, "Helvetica Neue", 微软雅黑, Tahoma, Arial, sans-serif;"> System.out.println(</span><span class="hljs-string" style="font-family: "Microsoft Yahei", "Hiragino Sans GB", Helvetica, "Helvetica Neue", 微软雅黑, Tahoma, Arial, sans-serif;">“Stransforming …”</span><span style="font-family: "Microsoft Yahei", "Hiragino Sans GB", Helvetica, "Helvetica Neue", 微软雅黑, Tahoma, Arial, sans-serif;">); </span><br/></p></li><li><p class="hljs-ln-numbers"><span style="font-family: "Microsoft Yahei", "Hiragino Sans GB", Helvetica, "Helvetica Neue", 微软雅黑, Tahoma, Arial, sans-serif;"> } </span><br/></p></li><li><p class="hljs-ln-numbers"><span style="font-family: "Microsoft Yahei", "Hiragino Sans GB", Helvetica, "Helvetica Neue", 微软雅黑, Tahoma, Arial, sans-serif;">}</span></p></li></ol>
( Composite /Aggregate ReusePrinciple(CARP): 소프트웨어 재사용의 목적을 달성하기 위해 상속 관계 대신 객체 조합을 사용해 보세요
Definition
종종 복합 재사용 원칙(Composite ReusePrinciple 또는 CRP)이라고도 합니다. 상속 관계 재사용 목적을 달성하기 위해 상속합니다.
새 개체의 일부 기존 개체를 사용하여 새 개체의 일부로 만드는 것은 새 개체가 이러한 개체에 위임하여 기존 기능을 재사용하는 목적을 달성하는 것입니다. 즉, 구성/집계를 사용하고 상속은 사용하지 마십시오.
원리 분석
1) 객체 지향 설계에서는 구성/집계 관계 또는 상속이라는 두 가지 기본 방법을 통해 기존 설계 및 구현을 다양한 환경에서 재사용할 수 있습니다.
상속 및 재사용: 구현이 간단하고 확장이 쉽습니다. 시스템의 캡슐화를 파괴합니다. 기본 클래스에서 상속된 구현은 정적이며 런타임에 변경할 수 없으며 제한된 환경에서만 사용할 수 있습니다. ("화이트 박스" 재사용)
구성/집계 재사용: 결합 정도가 상대적으로 낮고 멤버 개체의 작업이 선택적으로 호출되어 런타임에 동적으로 수행될 수 있습니다. ("블랙박스" 재사용)
2) 조합/집계는 시스템을 더 유연하게 만들고, 클래스 간의 결합을 줄일 수 있으며, 한 클래스의 변경 사항이 다른 클래스에 상대적으로 영향을 거의 미치지 않으므로 일반적으로 조합/집계가 선호됩니다. 두 번째로 상속을 고려하십시오. 상속을 사용할 때는 Liskov 대체 원칙을 엄격히 따라야 합니다. 상속을 효과적으로 사용하면 문제를 이해하고 복잡성을 줄이는 데 도움이 되는 반면, 상속을 남용하면 시스템 구축 및 유지 관리가 어려워집니다. 시스템이 복잡하기 때문에 상속 재사용을 주의 깊게 사용해야 합니다.
3) 이 원리와 Liskov 대체 원리는 서로 보완적입니다. 둘 다 "개방-폐쇄" 원리를 구체적으로 구현하기 위한 사양입니다. 이 원칙을 위반하면 "개방-폐쇄" 원칙이 실현될 수 없습니다. 먼저 합성과 집합의 개념을 이해해야 합니다.
참고: 집합과 조합의 차이점은 무엇인가요?
합성(결합): 전체와 부분의 관계를 나타내며, 전체를 기반으로 존재하는 관계(전체와 부분은 분리될 수 없음)를 나타냅니다. 예를 들어 눈과 입은 머리에 대한 결합 관계입니다. . 머리가 없으면 눈과 입도 없고, 둘은 뗄래야 뗄 수 없는 관계이다. UML에서 구성 관계는 실선 다이아몬드가 있는 직선으로 표시됩니다.
Aggregation: Aggregation은 종합 관계보다 종속 관계가 더 강하며, 나사와 자동차 장난감, 나사 사이의 관계와 같이 전체와 부분 사이의 관계(전체와 부분이 분리될 수 있음)를 나타냅니다. 나사를 다른 장치 위에서 분리한 후에도 장난감에 사용할 수 있습니다. UML에서 집계 관계는 빈 다이아몬드가 있는 직선으로 표시됩니다.
데메테르의 법칙
(데메테르의 법칙, LoD: 시스템의 클래스는 클래스 간의 결합을 줄이기 위해 다른 클래스와 상호 작용하지 않도록 노력해야 합니다.
정의
최소 지식의 원리라고도 합니다( 최소 지식 원칙(LKP) 여러 형태의 정의:
영어 정의는 다음과 같습니다. 낯선 사람과 대화하지 마세요.
직계 친구하고만 대화하세요.
각 소프트웨어 유닛은 다른 유닛에 대해 최소한의 지식만 갖고 있으며 자신의 유닛과 밀접하게 관련된 소프트웨어 유닛으로 제한됩니다.
간단히 말하자면, 객체는 다른 유닛에 대해서도 가능한 한 적게 알아야 합니다. 클래스는 결합하거나 호출해야 하는 클래스에 대해 최소한으로 알아야 합니다. 결합되거나 호출된 클래스의 내부가 얼마나 복잡한지는 나에게 중요하지 않습니다.
Law Analysis
친구 클래스:
데메테르의 법칙에서 그 친구들은 다음과 같은 카테고리를 포함합니다. 현재 객체 자체(this), (2) 매개변수 형태로 현재 객체 메소드에 전달된 객체, (3) 현재 객체의 멤버 객체, (4) 현재 객체가 세트인 경우, (5) 현재 객체에 의해 생성된 객체
위 조건 중 하나를 충족하는 모든 객체는 현재 객체의 "친구"이고, 그렇지 않으면 "낯선 사람"입니다.
협의의 Dimit의 법칙: 클래스 간의 결합을 줄일 수 있지만 시스템에 많은 문제가 발생합니다. 시스템 구석구석에 흩어져 있는 작은 방법은 각 부분이 멀리 있는 개체와 직접적으로 관련되지 않기 때문에 시스템의 로컬 설계를 단순화할 수 있지만 시스템의 서로 다른 모듈 간에 충돌을 일으키기도 합니다. 고가용성 아키텍처 설계를 위한 9가지 솔루션에 대한 자세한 설명을 보려면 여기를 클릭하세요.
일반화된 데메테르의 법칙: 정보 흐름, 흐름 및 객체 간 정보를 나타냅니다. 영향 제어는 주로 정보 은닉 제어에 있습니다. 정보 은닉은 각 하위 시스템을 분리하여 독립적으로 개발, 최적화, 사용 및 수정하는 동시에 소프트웨어의 재사용을 촉진할 수 있습니다. 존재 여부는 다른 모듈에 의존하므로 각 모듈은 다른 장소에서 독립적으로 사용될 수 있습니다. 시스템의 규모가 클수록 정보를 숨기는 것이 더 중요해지고 정보 숨기기의 중요성이 더욱 분명해집니다.
외관 모드 Facade(구조형)
Demeter의 법칙 및 디자인 패턴 Facade 모드, Mediator 모드
시스템의 클래스는 다른 클래스와 상호 작용하지 않고 클래스 간의 결합을 줄이려고 노력해야 합니다. 시스템에서 확장할 때 이러한 클래스를 수정해야 할 수 있으며 클래스는 다음과 관련되어 있기 때문입니다. 클래스 간의 관계는 수정의 복잡성을 결정합니다. 상호 작용이 많을수록 수정의 어려움이 커지고, 상호 작용이 작을수록 수정이 덜 어려워집니다. 예를 들어 클래스 A는 클래스 B에 종속되고 클래스 B는 클래스 C에 종속됩니다. 클래스 A를 수정할 때 클래스 B가 영향을 받을지, 클래스 B의 영향이 클래스 C에 영향을 미칠지 여부를 고려해야 합니다. 이때 C클래스가 D클래스에 종속된다면, ㅎㅎ 그런 수정은 감수할 수 있을 것 같습니다.
객체 지향 설계의 다른 원칙
#🎜 🎜# 캡슐화 변경상속을 줄이고 조합을 더 많이 사용구현 프로그래밍이 아닌 인터페이스를 위한 프로그래밍대화형 객체 간의 느슨한 결합 설계를 위해 노력# 🎜🎜#클래스는 확장 개발 및 수정에 폐쇄되어야 합니다(개방형 및 폐쇄형 OCP 원칙)
구체 클래스가 아닌 추상화에 의존(종속성 반전 DIP 원칙)
#🎜 🎜 #가까운 친구 원칙: 친구하고만 대화하세요(최소 지식의 원리, 소극의 법칙)설명: 객체는 다른 객체에 대해 가능한 한 적게 알아야 하며, 경계 내에서 메서드 호출을 유지하고 호출만 해야 합니다. 메소드는 다음 범위에 속합니다: 객체 자체(로컬 메소드) 객체의 구성요소는 메소드 매개변수로 전달됩니다. 이 메소드에 의해 생성되거나 인스턴스화된 모든 객체 찾지 마세요(전화하세요) I will find you (call you) (할리우드 원칙) A 클래스 변경 이유는 단 하나입니다(단일 책임 SRP 원칙)설명할 수 있나요? Liskov 대체 원칙에 대해
엄격한 정의: S 유형의 모든 객체 o1에 대해 T 유형의 객체 o2가 있으면 T로 정의된 모든 프로그램 P의 동작은 다음과 같습니다. 모든 객체가 o1에 의해 o2로 대체될 때 프로그램 P는 변경되지 않습니다. 그러면 유형 S는 유형 T의 하위 유형입니다.
대중적인 표현: 기본 클래스(상위 클래스)를 참조하는 모든 위치는 해당 하위 클래스의 개체를 투명하게 사용할 수 있어야 합니다. 즉, 하위 클래스는 상위 클래스의 기능을 확장할 수 있지만 상위 클래스의 원래 기능을 변경할 수는 없습니다. 여기에는 다음 4가지 의미 수준이 포함됩니다. Subclasses는 상위 클래스의 추상 메서드를 구현할 수 있지만 상위 클래스의 비추상 메서드를 재정의할 수는 없습니다. 서브클래스에 고유한 메서드를 추가할 수 있습니다. 하위 클래스의 메서드가 상위 클래스의 메서드를 재정의하는 경우 메서드의 전제 조건(즉, 메서드의 형식 매개 변수)은 상위 클래스 메서드의 입력 매개 변수보다 느슨합니다. 하위 클래스의 메서드가 상위 클래스의 추상 메서드를 구현할 때 메서드의 사후 조건(즉, 메서드의 반환 값)은 상위 클래스의 사후 조건보다 더 엄격합니다.어떤 상황에서 디밋의 법칙이 위반되나요? 이것이 왜 문제가 됩니까?
디미트의 법칙은 수업 간 결합을 줄이기 위해 "낯선 사람이 아닌 친구하고만 대화하라"고 권장합니다.
개방-폐쇄 원칙을 준수하는 디자인 패턴의 예를 들어주세요.
개방-폐쇄 원칙에 따르면 코드는 확장에 개방되고 수정에는 폐쇄되어야 합니다. 즉, 새로운 기능을 추가하려는 경우 이미 테스트된 코드를 변경하지 않고도 새 코드를 쉽게 추가할 수 있다는 의미입니다. 전략 패턴과 같이 개방-폐쇄 원칙을 기반으로 하는 여러 가지 디자인 패턴이 있습니다. 새로운 전략이 필요한 경우 핵심 로직을 변경하지 않고 인터페이스를 구현하고 구성을 추가하기만 하면 됩니다. 실제 예제는 Collections.sort() 메소드입니다. 이는 전략 패턴을 기반으로 하며 새 객체에 대해 sort() 메소드를 수정할 필요가 없습니다. 자신의 비교기 인터페이스.
플라이웨이트 모드(플라이 볼륨 모드)는 언제 사용하나요?
플라이웨이트 모드는 객체를 공유하여 너무 많은 객체를 생성하는 것을 방지합니다. 플라이웨이트 패턴을 사용하려면 객체를 안전하게 공유할 수 있도록 객체를 변경할 수 없는지 확인해야 합니다. JDK의 String 풀, Integer 풀 및 Long 풀은 모두 Flyweight 패턴을 사용하는 좋은 예입니다.
end:
궁금한 점이 있으면 물어보세요 나와서 모두와 소통하세요.
관련기사:
JavaScript가 꼭 알아야 할 기본지식
# 🎜🎜#24가지 디자인 패턴과 Java의 7가지 원칙
관련 동영상: # 🎜🎜# JavaScript 고급 프레임워크 디자인 비디오 튜토리얼
위 내용은 모든 Java 설계자는 이러한 6가지 디자인 원칙을 알고 있습니까? 마스터해야 함의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!