Die sechs Prinzipien von Entwurfsmustern: 1. Das Prinzip der Einzelverantwortung, dessen Kern darin besteht, die Granularit?t von Klassen zu kontrollieren, Objekte zu entkoppeln und ihren Zusammenhalt zu verbessern; 2. Das Prinzip des ?ffnens und Schlie?ens, das erreicht werden kann durch ? abstrakte Einschr?nkungen und Kapselungs?nderungen ?Zu erreichen; 3. Das Liskov-Substitutionsprinzip erkl?rt haupts?chlich einige Prinzipien der Vererbung; 4. Das Abh?ngigkeitsinversionsprinzip reduziert die Kopplung zwischen Clients und Implementierungsmodulen; 5. Das Schnittstellenisolationsprinzip besteht darin, Schnittstellen einzuschr?nken und Klassen zu reduzieren Paare. Abh?ngigkeiten von Schnittstellen 6. Das Demeter-Gesetz erfordert eine Begrenzung der Breite und Tiefe der Kommunikation zwischen Software-Entit?ten.
Die Betriebsumgebung dieses Tutorials: Windows7-System, Java8-Version, DELL G3-Computer.
In Bezug auf Designmuster habe ich vor langer Zeit viele Designmusterbücher gelesen und einige davon mehrmals gelesen. Ich habe immer gehofft, dass ich diese Designmuster beim Codieren verwenden kann. Bei der t?glichen Codierung wird jedoch am h?ufigsten der Singleton verwendet, gefolgt von den Beobachter- und Builder-Mustern (Builder), die h?ufiger verwendet werden, und die anderen werden seltener verwendet.
Der Grund, warum wir sie nicht verwenden k?nnen, ist, dass wir die Idee von Designmustern immer noch nicht verstehen und diese Designmuster nicht mit den beim Codieren auftretenden Problemen in Verbindung bringen k?nnen, sodass wir Designmuster nicht verwenden k?nnen.
Tats?chlich werden Entwurfsmuster vorgeschlagen, um ein h?ufiges Problem zu l?sen. Wenn Sie also darüber nachdenken, welches Designmuster Sie übernehmen m?chten, sollten Sie sich zun?chst fragen, wo das aktuelle Problem liegt. W?hlen Sie je nach Problem das passende Entwurfsmuster aus.
Nachdem Sie sich mit Designmustern vertraut gemacht haben, werden Sie feststellen, dass zwischen einigen Designmustern eine umfassende Beziehung besteht und sie sogar sehr ?hnlich sind, aber unterschiedliche Designmuster unterschiedliche Probleme l?sen.
Wenn wir ein Modul entwerfen, k?nnen wir es aus folgenden Perspektiven betrachten:
Welche Beziehung besteht zwischen diesem Modul und anderen Modulen?
Welche Teile des Moduls bleiben unver?ndert, welche Teile ?ndern sich st?ndig und wie?
Wie ist die Beziehung zwischen den Klassen? Warum müssen wir uns darauf verlassen?
M?chten Sie eine Schnittstelle hinzufügen? Welches Problem soll die Schnittstelle l?sen?
Natürlich lernen Sie in diesem Artikel nicht, wie Sie Designmuster verwenden. Es erkl?rt vielmehr die Designprinzipien von Designmustern. Auch Entwurfsmuster folgen bei der Gestaltung einigen Regeln.
Sechs Prinzipien von Entwurfsmustern, insbesondere wie folgt:
Einzelverantwortungsprinzip (Klassen und Methoden, Schnittstellen)
?ffnungs- und Schlie?prinzip (offen für Erweiterung, geschlossen für ?nderung)
-
Richter-Ersetzungsprinzip (Beziehung zwischen Basisklassen und Unterklassen)
Abh?ngigkeitsinversionsprinzip (verlassen Sie sich auf abstrakte Schnittstellen statt auf konkrete Objekte)
-
Schnittstellenisolationsprinzip (Schnittstellen werden nach Funktionen unterteilt)
Demeter-Gesetz (die enge Beziehung zwischen Klassen)
Neben jedem Gestaltungsprinzip befindet sich eine Klammer, die zur Erl?uterung bzw. Beschreibung des Anwendungsbereichs dient. Jedes Prinzip wird im Folgenden ausführlich beschrieben.
Definition des Single-Responsibility-Prinzips (Klasse, Methode, Schnittstelle)
Das Single-Responsibility-Prinzip (SRP) wird auch als Single-Function-Prinzip bezeichnet. Die Verantwortung bezieht sich hier auf den Grund für die ?nderung der Klasse. Das Prinzip der Einzelverantwortung legt fest, dass eine Klasse nur einen Grund für ihre ?nderung haben sollte, andernfalls sollte die Klasse aufgeteilt werden (Es sollte nie mehr als einen Grund für eine Klasse geben). ?ndern).
Dieses Prinzip besagt, dass Objekte nicht zu viele Verantwortlichkeiten übernehmen sollten. Wenn ein Objekt zu viele Verantwortlichkeiten übernimmt, gibt es mindestens die folgenden zwei Nachteile:
?nderungen in einer Verantwortung k?nnen diese Klasse schw?chen oder hemmen F?higkeit zur Implementierung anderer Verantwortlichkeiten;
Vorteile des Prinzips der Einzelverantwortung
Der Kern des Prinzips der Einzelverantwortung besteht darin, die Granularit?t von Klassen zu steuern, Objekte zu entkoppeln und ihren Zusammenhalt zu verbessern. Wenn Sie dem Prinzip der Einzelverantwortung folgen, haben Sie folgende Vorteile.
Reduzieren Sie die Komplexit?t des Kurses. Wenn eine Klasse nur für eine Verantwortlichkeit verantwortlich ist, ist ihre Logik definitiv viel einfacher, als wenn sie für mehrere Verantwortlichkeiten verantwortlich ist.Verbessern Sie die Lesbarkeit von Klassen. Die Komplexit?t wird reduziert und die Lesbarkeit natürlich verbessert.
Verbessern Sie die Wartbarkeit des Systems. Eine verbesserte Lesbarkeit erleichtert natürlich die Wartung.
Risikominderung durch Ver?nderungen. ?nderungen sind unvermeidlich, und wenn das Prinzip der Einzelverantwortung gut befolgt wird, k?nnen bei der ?nderung einer Funktion die Auswirkungen auf andere Funktionen erheblich reduziert werden.
So implementieren Sie das Prinzip der Einzelverantwortung
Das Prinzip der Einzelverantwortung ist das einfachste, aber am schwierigsten anzuwendende Prinzip. Es erfordert, dass Designer die verschiedenen Verantwortlichkeiten einer Klasse entdecken, sie trennen und dann zusammenfassen sie in verschiedene Klassen oder Module einteilen. Die vielf?ltigen Verantwortlichkeiten von Discovery-Klassen erfordern von Designern ausgepr?gte Analyse- und Designf?higkeiten sowie einschl?gige Refactoring-Erfahrung.
Beispiel
public interface UserService { public void login(String username, String password); public void register(String email, String username, String password); public void logError(String msg); public void sendEmail(String email); }
Dieser Code ist offensichtlich nicht nur für die Benutzerregistrierung und -anmeldung verantwortlich, sondern auch für die Protokollaufzeichnung und den E-Mail-Versand Das Verhalten der letzteren unterscheidet sich erheblich von dem der ersteren. <br/>
這段代碼很顯然存在很大的問題,UserService 既要負(fù)責(zé)用戶的注冊和登錄,還要負(fù)責(zé)日志的記錄和郵件的發(fā)送,并且后者的行為明顯區(qū)別于前者。<br/>
假設(shè)我要修改發(fā)送郵件的邏輯就得修改這個類,這時候 qa 還得回歸登錄注冊邏輯,這樣明顯不合理。
因此我們需要進(jìn)行拆分,根據(jù)具體的職能可將其具體拆分如下:
UserService:只負(fù)責(zé)登錄注冊
public interface UserService { public void login(String username, String password); public void register(String email, String username, String password); }
LogService :只負(fù)責(zé)日志<br/>
public interface LogService { public void logError(String msg); }
EmailService: 只負(fù)責(zé)發(fā)送郵件
public interface EmailService { public void sendEmail(String email); }
這時候,咱們再去回顧前面提到的優(yōu)點(diǎn),就能深深體會了。
這里只是講了接口,其實(shí)對類也一樣,甚至方法也是一樣的。
對于類來說,根據(jù)類名,確保里面提供的方法都是屬于這個類的。
對于方法,不要把不相關(guān)的對象實(shí)例作為參數(shù)傳進(jìn)來。如果你發(fā)現(xiàn)某個方法依賴某個不相關(guān)的對象,那么這個方法的實(shí)現(xiàn)可能就存在問題。
比如 android 中圖片下載后顯示到 imageView 中,我提供如下的方法:
loadImage(String url, ImageView view) { // 下載圖片,展示圖片 }
對于 loadImage 這個方法,參數(shù) url 是ok 的,但是參數(shù) ImageView 卻是不合理的。因?yàn)檫@里做了兩個操作,下載圖片,展示圖片。應(yīng)該將這個方法在進(jìn)行拆分:
// 下載圖片 loadImage(String url) { } // 顯示圖片 displayImage(String url, ImageView view) { // 調(diào)用 getBitmap (url) 獲取圖片 // 獲取圖片后將其設(shè)置到 view 中。 } // 根據(jù) url 獲取圖片, getBitmap(String url) { }
這樣整個邏輯就很清晰。后續(xù)需要修改下載邏輯,也不會影響到展示邏輯。當(dāng)然其實(shí)還有個問題是,這兩個方法要不要放在一個類里面?
開閉原則
開閉原則的實(shí)現(xiàn)方法:可以通過“抽象約束、封裝變化”來實(shí)現(xiàn)開閉原則,即通過接口或者抽象類為軟件實(shí)體定義一個相對穩(wěn)定的抽象層,而將相同的可變因素封裝在相同的具體實(shí)現(xiàn)類中。
因?yàn)槌橄箪`活性好,適應(yīng)性廣,只要抽象的合理,可以基本保持軟件架構(gòu)的穩(wěn)定。而軟件中易變的細(xì)節(jié)可以從抽象派生來的實(shí)現(xiàn)類來進(jìn)行擴(kuò)展,當(dāng)軟件需要發(fā)生變化時,只需要根據(jù)需求重新派生一個實(shí)現(xiàn)類來擴(kuò)展就可以了。
示例
// 矩形 public class Rectangle { public double getWidth() { return width; } public double getHeight() { return height; } }
需要計(jì)算矩形的面積
// 面積計(jì)算器 public class AreaCalculator { public double area(Rectangle shape){ return shape.getWidth() * shape.getHeight(); } }
假設(shè)這時候,又多了一個圓形類
// 圓形 public class Circular { public double getRadius(){ return radius; } }
同樣也需要計(jì)算他的面積,這時候就會變成下面這樣子:
public class AreaCalculator { public double area(Object shape){ if(shape instanceof Rectangle) { Rectangle rectangle = (Rectangle) shape; return rectangle.getWidth() * rectangle.getHeight(); } else if (shape instanceof Circular) { Circular circular = (Circular) shape; return circular.getRadius() * circular.getRadius() * Math.PI; } else { throw new RuntimeException("There is no such type."); } } }
這么更改完成,完全沒有問題。但是在真實(shí)的生產(chǎn)環(huán)境中,情況更為復(fù)雜,更改涉及的部分較多,那樣就可能導(dǎo)致牽一發(fā)動全身。并且,以前編寫的經(jīng)過測試的一些功能需要重新測試,甚至導(dǎo)致某些功能不可用。
改進(jìn)版,把計(jì)算面積這個公有邏輯變成一個接口:
public interface Shape { public double getArea(); } public class Rectangle implements Shape{ public double getWidth() { return width; } public double getHeight() { return height; } public double getArea() { return getWidth() * getHeight(); } }
這樣,當(dāng)需求變更,需要計(jì)算圓形面積的時候,我們只需創(chuàng)建一個圓形的類,并實(shí)現(xiàn) Shape 接口即可:<br/>
Angenommen, ich m?chte die Logik des E-Mail-Versands ?ndern, muss ich diese Klasse zu diesem Zeitpunkt ?ndern Anmelde- und Registrierungslogik, die offensichtlich unvernünftig ist.
Wir müssen es also entsprechend den spezifischen Funktionen aufteilen, es kann wie folgt aufgeteilt werden: ??????UserService??: nur für Anmeldung und Registrierung verantwortlich????public class Circular implements Shape { public double getRadius(){ return radius; } public double getArea() { return getRadius() * getRadius() * Math.PI; } }??????LogService: ??
class Customer { public void shopping(ShaoguanShop shop) { //購物 System.out.println(shop.sell()); } }??????EmailService??: Nur verantwortlich für das Versenden von E-Mails????
class Customer { public void shopping(WuyuanShop shop) { //購物 System.out.println(shop.sell()); } }????
Lassen Sie uns zu diesem Zeitpunkt die oben genannten Vorteile noch einmal durchgehen und Sie werden es tiefgreifend verstehen.
????Ich habe hier nur über Schnittstellen gesprochen. Tats?chlich ist es dasselbe für Klassen, und sogar die Methoden sind gleich. ????Stellen Sie bei Klassen basierend auf dem Klassennamen sicher, dass alle darin bereitgestellten Methoden zu dieser Klasse geh?ren. ????übergeben Sie bei Methoden keine irrelevanten Objektinstanzen als Parameter. Wenn Sie feststellen, dass eine Methode von einem nicht verwandten Objekt abh?ngt, liegt m?glicherweise ein Problem mit der Implementierung der Methode vor. ????Nachdem ich beispielsweise Bilder in Android heruntergeladen und in imageView angezeigt habe, stelle ich die folgende Methode bereit: ????class Customer { public void shopping(Shop shop) { //購物 System.out.println(shop.sell()); } } class Customer { public void shopping(Shop shop) { //購物 System.out.println(shop.sell()); } }????Für die Methode ?loadImage“ ist die Parameter-URL in Ordnung, aber der Parameter ?ImageView“ ist unangemessen. Denn hier werden zwei Vorg?nge ausgeführt: das Herunterladen von Bildern und das Anzeigen von Bildern. Diese Methode sollte aufgeteilt werden: ????
package principle; public class DIPtest { public static void main(String[] args) { Customer wang=new Customer(); System.out.println("顧客購買以下商品:"); wang.shopping(new ShaoguanShop()); wang.shopping(new WuyuanShop()); } } //商店 interface Shop { public String sell(); //賣 } //韶關(guān)網(wǎng)店 class ShaoguanShop implements Shop { public String sell() { return "韶關(guān)土特產(chǎn):香菇、木耳……"; } } //婺源網(wǎng)店 class WuyuanShop implements Shop { public String sell() { return "婺源土特產(chǎn):綠茶、酒糟魚……"; } } //顧客 class Customer { public void shopping(Shop shop) { //購物 System.out.println(shop.sell()); } }???? damit die gesamte Logik klar ist. Wenn Sie die Download-Logik sp?ter ?ndern müssen, hat dies keine Auswirkungen auf die Anzeigelogik. Natürlich gibt es tats?chlich noch eine andere Frage: Sollten diese beiden Methoden in eine Klasse eingeordnet werden? ??
???ffnungs- und Schlie?prinzip??
??So implementieren Sie das ?ffnungs- und Schlie?prinzip: Das ?ffnungs- und Schlie?prinzip kann durch ?abstrakte Einschr?nkungen und Kapselungs?nderungen“ realisiert werden, also durch Definieren von Software Entit?ten über Schnittstellen oder abstrakte Klassen Eine relativ stabile Abstraktionsschicht, die dieselben variablen Faktoren in derselben konkreten Implementierungsklasse kapselt.
????Da die Abstraktion eine gute Flexibilit?t und eine breite Anpassungsf?higkeit aufweist, kann die Stabilit?t der Softwarearchitektur grunds?tzlich aufrechterhalten werden, solange die Abstraktion angemessen ist. Die flüchtigen Details in der Software k?nnen aus der aus der Abstraktion abgeleiteten Implementierungsklasse erweitert werden. Wenn die Software ge?ndert werden muss, müssen Sie lediglich eine Implementierungsklasse entsprechend den Anforderungen zur Erweiterung neu ableiten. ??????Beispiel??????
顧客購買以下商品: 韶關(guān)土特產(chǎn):香菇、木耳…… 婺源土特產(chǎn):綠茶、酒糟魚……????
Die Fl?che eines Rechtecks ??muss berechnet werden
????public interface UserService { public void login(String username, String password); public void register(String email, String username, String password); public void logError(String msg); public void sendEmail(String email); }????Angenommen, zu diesem Zeitpunkt gibt es eine andere Kreisklasse ????
package principle; public class LoDtest { public static void main(String[] args) { Agent agent=new Agent(); agent.setStar(new Star("林心如")); agent.setFans(new Fans("粉絲韓丞")); agent.setCompany(new Company("中國傳媒有限公司")); agent.meeting(); agent.business(); } } //經(jīng)紀(jì)人 class Agent { private Star myStar; private Fans myFans; private Company myCompany; public void setStar(Star myStar) { this.myStar=myStar; } public void setFans(Fans myFans) { this.myFans=myFans; } public void setCompany(Company myCompany) { this.myCompany=myCompany; } public void meeting() { System.out.println(myFans.getName()+"與明星"+myStar.getName()+"見面了。"); } public void business() { System.out.println(myCompany.getName()+"與明星"+myStar.getName()+"洽淡業(yè)務(wù)。"); } } //明星 class Star { private String name; Star(String name) { this.name=name; } public String getName() { return name; } } //粉絲 class Fans { private String name; Fans(String name) { this.name=name; } public String getName() { return name; } } //媒體公司 class Company { private String name; Company(String name) { this.name=name; } public String getName() { return name; } }?? ??
Es ist auch notwendig, die Fl?che zu berechnen. Zu diesem Zeitpunkt sieht es so aus:
????粉絲韓丞與明星林心如見面了。 中國傳媒有限公司與明星林心如洽淡業(yè)務(wù)。????Nachdem diese ?nderung abgeschlossen ist ist überhaupt kein Problem. In einer realen Produktionsumgebung ist die Situation jedoch komplizierter und ?nderungen betreffen viele Teile, die sich auf den gesamten K?rper auswirken k?nnen. Au?erdem müssen einige zuvor geschriebene und getestete Funktionen erneut getestet werden, was sogar dazu führt, dass einige Funktionen nicht mehr verfügbar sind. ????Verbesserte Version, die die ?ffentliche Logik zur Fl?chenberechnung in eine Schnittstelle umwandelt: ????rrreee????
Wenn sich die Anforderungen ?ndern und wir die kreisf?rmige Fl?che berechnen müssen, k?nnen wir auf diese Weise Sie müssen lediglich eine zirkul?re Klasse erstellen und die Shape-Schnittstelle implementieren:<br/>
????rrreee??計(jì)算三角形面積、四邊形面積... 的時候,我們只需讓它們?nèi)?shí)現(xiàn) Shape 接口即可,無需修改源代碼。
Das Richter-Substitutionsprinzip
Das Richter-Substitutionsprinzip erkl?rt haupts?chlich einige Prinzipien zur Vererbung, das hei?t, wann Vererbung genutzt werden sollte, wann Vererbung nicht genutzt werden sollte und welche Prinzipien ihr zugrunde liegen. Die Liskov-Substitution ist ursprünglich die Grundlage für die Wiederverwendung der Vererbung. Sie spiegelt die Beziehung zwischen Basisklassen und Unterklassen wider, erg?nzt das ?ffnungs- und Schlie?prinzip und regelt die spezifischen Schritte zur Erzielung einer Abstraktion.
Die Rolle des Richter-Substitutionsprinzips
Die Hauptfunktionen des Richter-Substitutionsprinzips sind wie folgt.
Das Richter-Substitutionsprinzip ist eine der wichtigen M?glichkeiten, das Er?ffnungs- und Schlussprinzip zu verwirklichen.
Es überwindet die M?ngel der schlechten Wiederverwendbarkeit, die durch das überschreiben übergeordneter Klassen bei der Vererbung verursacht werden.
Es ist die Garantie für die Richtigkeit der Aktion. Das hei?t, durch die Erweiterung der Klasse werden keine neuen Fehler in das bestehende System eingeführt, wodurch die M?glichkeit von Codefehlern verringert wird.
St?rken Sie die Robustheit des Programms und erreichen Sie gleichzeitig eine sehr gute Kompatibilit?t bei ?nderungen, verbessern Sie die Wartbarkeit und Skalierbarkeit des Programms und reduzieren Sie die Risiken, die bei sich ?ndernden Anforderungen entstehen.
So implementieren Sie das Richter-Substitutionsprinzip (Vererbung)
Das Richter-Substitutionsprinzip lautet im Allgemeinen: Unterklassen k?nnen die Funktionen der übergeordneten Klasse erweitern, jedoch nicht die ursprünglichen Funktionen der übergeordneten Klasse ?ndern. Mit anderen Worten: Wenn eine Unterklasse eine übergeordnete Klasse erbt, versuchen Sie, die Methoden der übergeordneten Klasse nicht zu überschreiben, au?er durch das Hinzufügen neuer Methoden zur Vervollst?ndigung neuer Funktionen.
Basierend auf dem obigen Verst?ndnis kann die Definition des Liskov-Substitutionsprinzips wie folgt zusammengefasst werden:
Eine Unterklasse kann die abstrakte Methode der übergeordneten Klasse implementieren, aber die nicht abstrakte Methode der übergeordneten Klasse nicht überschreiben Klasse
In der Unterklasse k?nnen Sie Ihre eigenen eindeutigen Methoden hinzufügen
Wenn eine Methode einer Unterklasse eine Methode einer übergeordneten Klasse überschreibt, werden die Vorbedingungen der Methode (d. h. die Eingabeparameter der Methode) überschrieben ) sind lockerer als die Methode der übergeordneten Klasse
Wenn eine Methode einer Unterklasse eine Methode einer übergeordneten Klasse implementiert (eine abstrakte Methode überschreibt/überl?dt oder implementiert), sind die Nachbedingungen der Methode (d. h. die Ausgabe/ Rückgabewert der Methode) sind strenger oder gleich denen der übergeordneten Klasse
Obwohl es einfach ist, neue Funktionen durch Umschreiben der übergeordneten Klassenmethode zu schreiben, ist die Wiederverwendbarkeit des gesamten Vererbungssystems relativ schlecht Da Polymorphismus h?ufig verwendet wird, ist die Wahrscheinlichkeit von Fehlern bei der Programmausführung sehr hoch.
Wenn das Programm gegen das Liskov-Substitutionsprinzip verst??t, weist das Objekt der geerbten Klasse dort, wo die Basisklasse erscheint, einen Laufzeitfehler auf.
Die Korrekturmethode zu diesem Zeitpunkt besteht darin, die ursprüngliche Vererbungsbeziehung aufzuheben und die Beziehung zwischen ihnen neu zu gestalten.
Was das Liskov-Substitutionsprinzip betrifft, so ist das bekannteste Beispiel ?Ein Quadrat ist kein Rechteck“. Natürlich gibt es viele ?hnliche Beispiele im Leben, zum Beispiel werden Pinguine, Strau?e und Kiwis aus biologischer Sicht als V?gel klassifiziert, aber aus einer Klassenvererbungsbeziehung, weil sie die ?Vogel“-F?higkeit, zu fliegen, nicht erben k?nnen k?nnen nicht als Unterklassen von ?bird“ definiert werden. Da ?Ballonfische“ nicht schwimmen k?nnen, k?nnen sie auch nicht als Unterkategorie von ?Fischen“ definiert werden; ?Spielzeugkanonen“ k?nnen keine Feinde in die Luft jagen, also k?nnen sie nicht als Unterkategorie von ?Kanonen“ usw. definiert werden.
Der beste Weg für Quadrate und Rechtecke besteht darin, eine weitere übergeordnete Klasse hinzuzufügen und sie gleichzeitig von dieser übergeordneten Klasse zu erben.
Abh?ngigkeitsumkehr (Drahtzeichnungsdetails)
Das Prinzip der Abh?ngigkeitsumkehr ist eine der wichtigen M?glichkeiten zur Implementierung des Open-Close-Prinzips, das die Kopplung zwischen Clients und Implementierungsmodulen reduziert.
Da beim Softwaredesign Details ver?nderbar sind, w?hrend die Abstraktionsschicht relativ stabil ist, ist eine auf Abstraktion basierende Architektur viel stabiler als eine auf Details basierende Architektur. Die Zusammenfassung bezieht sich hier auf die Schnittstelle oder abstrakte Klasse, und die Details beziehen sich auf die spezifische Implementierungsklasse.
Der Zweck der Verwendung von Schnittstellen oder abstrakten Klassen besteht darin, Spezifikationen und Vertr?ge zu formulieren, ohne dass bestimmte Vorg?nge erforderlich sind, und die Aufgabe, die Details anzuzeigen, ihren Implementierungsklassen zu überlassen.
Die Funktionen des Abh?ngigkeits- und Umkehrprinzips
Die Hauptfunktionen des Abh?ngigkeitsinversionsprinzips sind wie folgt.
Das Prinzip der Abh?ngigkeitsumkehr kann die Kopplung zwischen Klassen verringern.
Das Abh?ngigkeitsinversionsprinzip kann die Stabilit?t des Systems verbessern.
Das Abh?ngigkeitsinversionsprinzip kann die durch parallele Entwicklung verursachten Risiken verringern.
Das Abh?ngigkeitsinversionsprinzip kann die Lesbarkeit und Wartbarkeit von Code verbessern.
依賴倒置原則的實(shí)現(xiàn)方法
依賴倒置原則的目的是通過要面向接口的編程來降低類間的耦合性,所以我們在實(shí)際編程中只要遵循以下4點(diǎn),就能在項(xiàng)目中滿足這個規(guī)則。
每個類盡量提供接口或抽象類,或者兩者都具備。
變量的聲明類型盡量是接口或者是抽象類。
任何類都不應(yīng)該從具體類派生。
使用繼承時盡量遵循里氏替換原則。
依賴倒置原則在“顧客購物程序”中的應(yīng)用。
分析:本程序反映了 “顧客類”與“商店類”的關(guān)系。商店類中有 sell() 方法,顧客類通過該方法購物以下代碼定義了顧客類通過韶關(guān)網(wǎng)店 ShaoguanShop 購物
class Customer { public void shopping(ShaoguanShop shop) { //購物 System.out.println(shop.sell()); } }
但是,這種設(shè)計(jì)存在缺點(diǎn),如果該顧客想從另外一家商店(如婺源網(wǎng)店 WuyuanShop)購物,就要將該顧客的代碼修改如下:
class Customer { public void shopping(WuyuanShop shop) { //購物 System.out.println(shop.sell()); } }
顧客每更換一家商店,都要修改一次代碼,這明顯違背了開閉原則。
存在以上缺點(diǎn)的原因是:顧客類設(shè)計(jì)時同具體的商店類綁定了,這違背了依賴倒置原則。
解決方法是:定義“婺源網(wǎng)店”和“韶關(guān)網(wǎng)店”的共同接口 Shop,顧客類面向該接口編程,其代碼修改如下:
class Customer { public void shopping(Shop shop) { //購物 System.out.println(shop.sell()); } } class Customer { public void shopping(Shop shop) { //購物 System.out.println(shop.sell()); } }
這樣,不管顧客類 Customer 訪問什么商店,或者增加新的商店,都不需要修改原有代碼了,其類如下圖所示:
package principle; public class DIPtest { public static void main(String[] args) { Customer wang=new Customer(); System.out.println("顧客購買以下商品:"); wang.shopping(new ShaoguanShop()); wang.shopping(new WuyuanShop()); } } //商店 interface Shop { public String sell(); //賣 } //韶關(guān)網(wǎng)店 class ShaoguanShop implements Shop { public String sell() { return "韶關(guān)土特產(chǎn):香菇、木耳……"; } } //婺源網(wǎng)店 class WuyuanShop implements Shop { public String sell() { return "婺源土特產(chǎn):綠茶、酒糟魚……"; } } //顧客 class Customer { public void shopping(Shop shop) { //購物 System.out.println(shop.sell()); } }
程序的運(yùn)行結(jié)果如下:
顧客購買以下商品: 韶關(guān)土特產(chǎn):香菇、木耳…… 婺源土特產(chǎn):綠茶、酒糟魚……
Interface Segregation Principle (Interface)
Interface Segregation Principle (ISP) erfordert, dass Programmierer ihr Bestes geben, um aufgebl?hte Schnittstellen in kleinere und spezifischere Schnittstellen aufzuteilen, sodass die Schnittstelle nur die für den Kunden interessante Methode enth?lt.
Im Jahr 2002 definierte Robert C. Martin das ?Interface Isolation Prinzip“ wie folgt: Clients sollten nicht gezwungen werden, sich auf Methoden zu verlassen, die sie nicht verwenden (Clients sollten nicht gezwungen werden, sich auf Methoden zu verlassen, die sie nicht verwenden). Es gibt eine andere Definition dieses Prinzips: Die Abh?ngigkeit einer Klasse zu einer anderen sollte von der kleinstm?glichen Schnittstelle abh?ngen.
Die Bedeutung der beiden oben genannten Definitionen besteht darin, die dedizierten Schnittstellen einzurichten, die sie für jede Klasse ben?tigen, anstatt zu versuchen, eine riesige Schnittstelle für alle Klassen zu erstellen, deren Aufruf davon abh?ngt.
Das Prinzip der Schnittstellenisolation und das Prinzip der Einzelverantwortung dienen beide dazu, den Zusammenhalt der Klassen zu verbessern und die Kopplung zwischen ihnen zu verringern, was die Idee der Kapselung verk?rpert, aber die beiden sind unterschiedlich:
Der Schwerpunkt liegt auf dem Prinzip der Einzelverantwortung auf Verantwortlichkeiten, w?hrend das Schnittstellenisolationsprinzip auf die Isolierung von Schnittstellenabh?ngigkeiten abzielt.
Das Prinzip der Einzelverantwortung schr?nkt haupts?chlich Klassen ein, die auf die Implementierung und Details des Programms abzielen. Das Prinzip der Schnittstellenisolation schr?nkt haupts?chlich Schnittstellen ein, haupts?chlich für die Konstruktion der Abstraktion und des Gesamtrahmens des Programms.
Vorteile des Schnittstellenisolationsprinzips
Das Schnittstellenisolationsprinzip besteht darin, Schnittstellen einzuschr?nken und die Abh?ngigkeit von Klassen von Schnittstellen zu verringern, was die folgenden 5 Vorteile bietet.
Zerlegen Sie die aufgebl?hte Schnittstelle in mehrere Schnittstellen mit geringer Granularit?t auf, um die Ausbreitung externer ?nderungen zu verhindern und die Flexibilit?t und Wartbarkeit des Systems zu verbessern.
Die Schnittstellenisolation verbessert den Zusammenhalt des Systems, reduziert externe Interaktionen und verringert die Kopplung des Systems.
Wenn die Granularit?t der Schnittstelle angemessen definiert ist, kann die Stabilit?t des Systems gew?hrleistet werden. Wenn die Definition jedoch zu klein ist, führt dies zu zu vielen Schnittstellen und verkompliziert das Design Im Gro?en und Ganzen wird die Flexibilit?t eingeschr?nkt. Die Unf?higkeit, ma?geschneiderte Dienstleistungen bereitzustellen, birgt unvorhergesehene Risiken für das Gesamtprojekt.
Die Verwendung mehrerer spezialisierter Schnittstellen kann auch die Hierarchie von Objekten widerspiegeln, da die Definition der Gesamtschnittstelle durch Schnittstellenvererbung erreicht werden kann.
kann Code-Redundanz in der Projektentwicklung reduzieren. Eine zu gro?e Schnittstelle enth?lt normalerweise viele ungenutzte Methoden. Bei der Implementierung dieser Schnittstelle sind Sie gezwungen, redundanten Code zu entwerfen.
So implementieren Sie das Schnittstellenisolationsprinzip
Bei der konkreten Anwendung des Schnittstellenisolationsprinzips sollte es gem?? den folgenden Regeln gemessen werden.
Die Schnittstelle sollte m?glichst klein sein, aber in Grenzen. Eine Schnittstelle bedient nur ein Untermodul oder eine Gesch?ftslogik.
Passen Sie Dienste für Klassen an, die auf Schnittstellen basieren. Stellen Sie nur die Methoden bereit, die der Aufrufer ben?tigt, und blockieren Sie die Methoden, die nicht ben?tigt werden.
Verstehen Sie die Umgebung und weigern Sie sich, blind zu folgen. Jedes Projekt oder Produkt verfügt über ausgew?hlte Umgebungsfaktoren. Verschiedene Umgebungen haben unterschiedliche Standards für die Schnittstellenaufteilung. Verstehen Sie die Gesch?ftslogik im Detail.
Verbessern Sie den Zusammenhalt und reduzieren Sie externe Interaktionen. Stellen Sie sicher, dass die Schnittstelle die wenigsten Methoden verwendet, um die meisten Aufgaben zu erledigen.
Für die Schnittstellenisolation k?nnen Sie sich weiterhin auf das in der Einzelverantwortung genannte Beispiel beziehen:
public interface UserService { public void login(String username, String password); public void register(String email, String username, String password); public void logError(String msg); public void sendEmail(String email); }
這時候,應(yīng)該就能理解拆分的好處了。
迪米特法則 (類與類之間的關(guān)系)
迪米特法則(Law of Demeter,LoD)又叫作最少知識原則(Least Knowledge Principle,LKP),產(chǎn)生于 1987 年美國東北大學(xué)(Northeastern University)的一個名為迪米特(Demeter)的研究項(xiàng)目,由伊恩·荷蘭(Ian Holland)提出,被 UML 創(chuàng)始者之一的布奇(Booch)普及,后來又因?yàn)樵诮?jīng)典著作《程序員修煉之道》(The Pragmatic Programmer)提及而廣為人知。
迪米特法則的定義是:只與你的直接朋友交談,不跟“陌生人”說話(Talk only to your immediate friends and not to strangers)。其含義是:如果兩個軟件實(shí)體無須直接通信,那么就不應(yīng)當(dāng)發(fā)生直接的相互調(diào)用,可以通過第三方轉(zhuǎn)發(fā)該調(diào)用。其目的是降低類之間的耦合度,提高模塊的相對獨(dú)立性。
迪米特法則中的“朋友”是指:當(dāng)前對象本身、當(dāng)前對象的成員對象、當(dāng)前對象所創(chuàng)建的對象、當(dāng)前對象的方法參數(shù)等,這些對象同當(dāng)前對象存在關(guān)聯(lián)、聚合或組合關(guān)系,可以直接訪問這些對象的方法。
迪米特法則的優(yōu)點(diǎn)
迪米特法則要求限制軟件實(shí)體之間通信的寬度和深度,正確使用迪米特法則將有以下兩個優(yōu)點(diǎn)。
降低了類之間的耦合度,提高了模塊的相對獨(dú)立性。
由于親合度降低,從而提高了類的可復(fù)用率和系統(tǒng)的擴(kuò)展性。
但是,過度使用迪米特法則會使系統(tǒng)產(chǎn)生大量的中介類,從而增加系統(tǒng)的復(fù)雜性,使模塊之間的通信效率降低。所以,在釆用迪米特法則時需要反復(fù)權(quán)衡,確保高內(nèi)聚和低耦合的同時,保證系統(tǒng)的結(jié)構(gòu)清晰。
迪米特法則的實(shí)現(xiàn)方法
從迪米特法則的定義和特點(diǎn)可知,它強(qiáng)調(diào)以下兩點(diǎn):
從依賴者的角度來說,只依賴應(yīng)該依賴的對象。
從被依賴者的角度說,只暴露應(yīng)該暴露的方法。
所以,在運(yùn)用迪米特法則時要注意以下 6 點(diǎn)。
在類的劃分上,應(yīng)該創(chuàng)建弱耦合的類。類與類之間的耦合越弱,就越有利于實(shí)現(xiàn)可復(fù)用的目標(biāo)。
在類的結(jié)構(gòu)設(shè)計(jì)上,盡量降低類成員的訪問權(quán)限。
在類的設(shè)計(jì)上,優(yōu)先考慮將一個類設(shè)置成不變類。
在對其他類的引用上,將引用其他對象的次數(shù)降到最低。
不暴露類的屬性成員,而應(yīng)該提供相應(yīng)的訪問器(set 和 get 方法)。
謹(jǐn)慎使用序列化(Serializable)功能
明星與經(jīng)紀(jì)人的關(guān)系實(shí)例。
分析:明星由于全身心投入藝術(shù),所以許多日常事務(wù)由經(jīng)紀(jì)人負(fù)責(zé)處理,如與粉絲的見面會,與媒體公司的業(yè)務(wù)洽淡等。這里的經(jīng)紀(jì)人是明星的朋友,而粉絲和媒體公司是陌生人,所以適合使用迪米特法則,其類圖如下圖所示。
package principle; public class LoDtest { public static void main(String[] args) { Agent agent=new Agent(); agent.setStar(new Star("林心如")); agent.setFans(new Fans("粉絲韓丞")); agent.setCompany(new Company("中國傳媒有限公司")); agent.meeting(); agent.business(); } } //經(jīng)紀(jì)人 class Agent { private Star myStar; private Fans myFans; private Company myCompany; public void setStar(Star myStar) { this.myStar=myStar; } public void setFans(Fans myFans) { this.myFans=myFans; } public void setCompany(Company myCompany) { this.myCompany=myCompany; } public void meeting() { System.out.println(myFans.getName()+"與明星"+myStar.getName()+"見面了。"); } public void business() { System.out.println(myCompany.getName()+"與明星"+myStar.getName()+"洽淡業(yè)務(wù)。"); } } //明星 class Star { private String name; Star(String name) { this.name=name; } public String getName() { return name; } } //粉絲 class Fans { private String name; Fans(String name) { this.name=name; } public String getName() { return name; } } //媒體公司 class Company { private String name; Company(String name) { this.name=name; } public String getName() { return name; } }
程序的運(yùn)行結(jié)果如下:
粉絲韓丞與明星林心如見面了。 中國傳媒有限公司與明星林心如洽淡業(yè)務(wù)。
?到此,設(shè)計(jì)模式的六大原則就講完了。
更多編程相關(guān)知識,請?jiān)L問:編程教學(xué)?。?/p>
Das obige ist der detaillierte Inhalt vonWas sind die sechs Prinzipien von Designmustern?. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Hei?e KI -Werkzeuge

Undress AI Tool
Ausziehbilder kostenlos

Undresser.AI Undress
KI-gestützte App zum Erstellen realistischer Aktfotos

AI Clothes Remover
Online-KI-Tool zum Entfernen von Kleidung aus Fotos.

Clothoff.io
KI-Kleiderentferner

Video Face Swap
Tauschen Sie Gesichter in jedem Video mühelos mit unserem v?llig kostenlosen KI-Gesichtstausch-Tool aus!

Hei?er Artikel

Hei?e Werkzeuge

Notepad++7.3.1
Einfach zu bedienender und kostenloser Code-Editor

SublimeText3 chinesische Version
Chinesische Version, sehr einfach zu bedienen

Senden Sie Studio 13.0.1
Leistungsstarke integrierte PHP-Entwicklungsumgebung

Dreamweaver CS6
Visuelle Webentwicklungstools

SublimeText3 Mac-Version
Codebearbeitungssoftware auf Gottesniveau (SublimeText3)

Im Java-Framework besteht der Unterschied zwischen Entwurfsmustern und Architekturmustern darin, dass Entwurfsmuster abstrakte L?sungen für h?ufige Probleme beim Softwaredesign definieren und sich dabei auf die Interaktion zwischen Klassen und Objekten konzentrieren, beispielsweise Fabrikmuster. Architekturmuster definieren die Beziehung zwischen Systemstrukturen und Modulen und konzentrieren sich auf die Organisation und Interaktion von Systemkomponenten, wie z. B. eine geschichtete Architektur.

TDD wird verwendet, um hochwertigen PHP-Code zu schreiben. Die Schritte umfassen: Testf?lle schreiben, die erwartete Funktionalit?t beschreiben und sie zum Scheitern bringen. Schreiben Sie Code so, dass nur die Testf?lle ohne überm??ige Optimierung oder detailliertes Design erfolgreich sind. Nachdem die Testf?lle bestanden wurden, optimieren und überarbeiten Sie den Code, um die Lesbarkeit, Wartbarkeit und Skalierbarkeit zu verbessern.

Das Guice-Framework wendet eine Reihe von Entwurfsmustern an, darunter: Singleton-Muster: Durch die @Singleton-Annotation wird sichergestellt, dass eine Klasse nur eine Instanz hat. Factory-Methodenmuster: Erstellen Sie eine Factory-Methode über die Annotation @Provides und rufen Sie die Objektinstanz w?hrend der Abh?ngigkeitsinjektion ab. Strategiemodus: Kapseln Sie den Algorithmus in verschiedene Strategieklassen und geben Sie die spezifische Strategie über die Annotation @Named an.

Das Dekoratormuster ist ein strukturelles Entwurfsmuster, das das dynamische Hinzufügen von Objektfunktionen erm?glicht, ohne die ursprüngliche Klasse zu ?ndern. Es wird durch die Zusammenarbeit von abstrakten Komponenten, konkreten Komponenten, abstrakten Dekoratoren und konkreten Dekoratoren implementiert und kann Klassenfunktionen flexibel erweitern, um sich ?ndernden Anforderungen gerecht zu werden. In diesem Beispiel werden Milch- und Mokka-Dekoratoren zu Espresso für einen Gesamtpreis von 2,29 $ hinzugefügt, was die Leistungsf?higkeit des Dekoratormusters bei der dynamischen ?nderung des Verhaltens von Objekten demonstriert.

Das SpringMVC-Framework verwendet die folgenden Entwurfsmuster: 1. Singleton-Modus: verwaltet den Spring-Container; 2. Fassadenmodus: koordiniert Controller-, Ansichts- und Modellinteraktion; 3. Strategiemodus: w?hlt einen Anforderungshandler basierend auf der Anforderung aus; : Ver?ffentlicht und wartet auf Anwendungsereignisse. Diese Entwurfsmuster verbessern die Funktionalit?t und Flexibilit?t von SpringMVC und erm?glichen Entwicklern die Erstellung effizienter und wartbarer Anwendungen.

Zu den Vorteilen der Verwendung von Entwurfsmustern in Java-Frameworks geh?ren: verbesserte Lesbarkeit, Wartbarkeit und Skalierbarkeit des Codes. Zu den Nachteilen geh?ren Komplexit?t, Leistungsaufwand und eine steile Lernkurve aufgrund überm??iger Nutzung. Praktischer Fall: Der Proxy-Modus wird zum verz?gerten Laden von Objekten verwendet. Setzen Sie Entwurfsmuster mit Bedacht ein, um ihre Vorteile zu nutzen und ihre Nachteile zu minimieren.

PHP-Entwurfsmuster bieten bekannte L?sungen für h?ufige Probleme in der Softwareentwicklung. Zu den g?ngigen Mustertypen geh?ren sch?pferische Muster (z. B. Fabrikmethodenmuster), strukturelle Muster (z. B. Dekorationsmuster) und Verhaltensmuster (z. B. Beobachtermuster). Entwurfsmuster sind besonders nützlich, wenn es darum geht, sich wiederholende Probleme zu l?sen, die Wartbarkeit zu verbessern und die Teamarbeit zu f?rdern. In E-Commerce-Systemen kann das Beobachtermuster automatische Aktualisierungen zwischen Warenkorb- und Bestellstatus realisieren. Insgesamt sind PHP-Entwurfsmuster ein wichtiges Werkzeug zum Erstellen robuster, skalierbarer und wartbarer Anwendungen.

TDD und Entwurfsmuster verbessern die Codequalit?t und Wartbarkeit. TDD stellt die Testabdeckung sicher, verbessert die Wartbarkeit und verbessert die Codequalit?t. Entwurfsmuster unterstützen TDD durch Prinzipien wie lose Kopplung und hohe Koh?sion und stellen sicher, dass Tests alle Aspekte des Anwendungsverhaltens abdecken. Es verbessert auch die Wartbarkeit und Codequalit?t durch Wiederverwendbarkeit, Wartbarkeit und robusteren Code.
