成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

Java編程中必知必會的五條SOLID原則

開發(fā) 后端
在本文中,我們介紹SOLID原則的核心內(nèi)容,并幫助您理解這些原則如何應用到項目中。

在面向?qū)ο缶幊蹋∣OP)領域,SOLID原則是類設計的指導準則。這五個原則形成了一套規(guī)則和最佳實踐,開發(fā)人員在設計類結構時應遵循這些原則。通過理解和應用這些原則,我們可以發(fā)揮出設計模式的潛力,創(chuàng)建強大的軟件架構。

在本文中,我們介紹SOLID原則的核心內(nèi)容,并幫助您理解這些原則如何應用到項目中。

核心目標:編寫可理解、無回歸和可測試的代碼

SOLID原則的核心目標是構建可理解、無回歸、可讀和可測試的代碼。這些代碼作為一個畫布,多個開發(fā)人員可以輕松地進行協(xié)作,促進生產(chǎn)力和創(chuàng)新的環(huán)境。

現(xiàn)在,我們逐個深入討論SOLID原則,揭示它們在塑造類設計中的重要性。

  • S — 單一責任原則
  • O — 開放封閉原則
  • L — 里氏替換原則
  • I — 接口隔離原則
  • D — 依賴反轉(zhuǎn)原則

1. 單一責任原則

SOLID的第一個支柱,單一責任原則(SRP),強調(diào)一個類應該只有一個變化的原因。遵循這個原則,我們確保每個類只負責一個任務,可使將來的維護和修改更容易。

/*手機類,具有屬性和構造函數(shù)*/
Class MobilePhone{
    String brandName;
    Float price;
    Date manufactureDate;
  public MobilePhone(String brandName,Float price,Date manufactureDate){
      this.brandName=brandName;
      this.price=price;
      this.manufactureDate=manufactureDate;
  }
};

/*Invoice類擁有一個手機(mobile phone)和該手機的數(shù)量(quantity)*/
Class Invoice{
    private MobilePhone mPhone;
    int quantity;
  public Invoice(MobilePhone mPhone,quantity){
    this.mPhone=mPhone;
    this.quantity=quantity;
  }
  public float calculateTotalPrice(){
    return mPhone.price*this.quantity;//返回發(fā)票的總金額
  }
  public void printInvoice(){
    //打印發(fā)票的邏輯
  }
  public void sendNotification(){
    //發(fā)送通知的邏輯
  }

}

以上代碼,與計算、打印或通知邏輯相關的任何更改都需要修改Invoice類。因此,發(fā)票類缺乏明確的關注點分離,對一個方面的修改會影響到其他功能。為了遵循SRP,關鍵是將Invoice類重構為更小、更專注的類, 每個類都獨立處理特定的職責,比如計算、打印或通知邏輯。

根據(jù)職責將代碼分離成獨立的類是遵循單一責任原則(SRP)并促進可維護和靈活的代碼庫的正確方法。

在這種設計中,我們應該有:

  • Invoice類只包含計算邏輯。
  • InvoicePrint類只包含打印邏輯。
  • InvoiceNotify類只包含發(fā)送通知的邏輯。
/*手機類,具有屬性和構造函數(shù)*/
Class MobilePhone{
    String brandName;
    Float price;
    Date manufactureDate;
  public MobilePhone(String brandName,Float price,Date manufactureDate){
      this.brandName=brandName;
      this.price=price;
      this.manufactureDate=manufactureDate;
  }
};

/*發(fā)票類,擁有手機和數(shù)量屬性*/
Class Invoice{
    private MobilePhone mPhone;
    int quantity;
  public Invoice(MobilePhone mPhone,quantity){
    this.mPhone=mPhone;
    this.quantity=quantity;
  }
  public float calculateTotalPrice(){
    return mPhone.price*this.quantity;//返回發(fā)票的總金額
  }
}

Class InvoicePrint{
  private Invoice invoice;
  
  public InvoicePrint(Invoice invoice){
  this.invoice=invoice
  }
  public void printInvoice(){
    //打印發(fā)票的邏輯
  }
}/*如果打印邏輯發(fā)生變化,只有InvoicePrint類會發(fā)生變化。*/
Class InvoiceNotify{
  private Invoice invoice;
  
  public InvoiceNotify(Invoice invoice){
  this.invoice=invoice
  public void sendNotification(){
    //發(fā)送通知給用戶的邏輯
  }
}/*如果通知邏輯發(fā)生變化,只有InvoiceNotify類會發(fā)生變化。*/

2. 開放-封閉原則

第二個原則是開放-封閉原則(OCP),它鼓勵軟件實體對擴展開放,但對修改封閉。換句話說,一旦一個類被建立,它應該能夠輕松地進行擴展,而不需要修改其現(xiàn)有的代碼。這促進了代碼的重用和穩(wěn)定性。

讓我們以上面使用的InvoiceNotify類為例,InvoiceNotify類經(jīng)過測試,并且當前在客戶端中實際使用,通過電子郵件發(fā)送發(fā)票通知。

現(xiàn)在有一個客戶需求,他們需要通過推送通知發(fā)送通知。

Class InvoiceNotify{
  private Invoice invoice;
  
  public InvoiceNotify(Invoice invoice){
  this.invoice=invoice
  public void sendNotification(){
    //發(fā)送通知給用戶的邏輯
  }
  public void sendPushNotification(){
    //發(fā)送推送通知給用戶的邏輯
  }
}

以上代碼,通過在現(xiàn)有類中添加一個新方法,我們違反了開放/封閉原則

與其在現(xiàn)有類中添加一個新方法,我們應該設計一個接口并在各個類中實現(xiàn)。

Interface InvoiceNotification{
 public void sendNotification();
}
Class EmailNotification implements InvoiceNotification{
 private Invoice invoice;
  public EmailNotification(Invoice invoice){
     this.invoice=invoice;
  }
  @Override
  public void sendNotification(){
  //通過電子郵件發(fā)送通知的邏輯
  }
}
Class PushNotification implements InvoiceNotification{
 private Invoice invoice;
  public PushNotification(Invoice invoice){
     this.invoice=invoice;
  }
  @Override
  public void sendNotification(){
  //發(fā)送推送通知的邏輯
  }
}

如果進一步增強需求,需要通過短信發(fā)送通知,無需修改現(xiàn)有類。相反,我們可以創(chuàng)建一個名為TextNotification的新類,它實現(xiàn)了InvoiceNotification接口并重寫了sendNotification()方法。這樣,我們就能夠順利地集成新功能,而不會破壞現(xiàn)有的代碼庫。

3. 里氏替換原則

里氏替換原則(LSP)定義了基類和派生類之間的契約。它規(guī)定派生類應該能夠替代其基類,而不會影響程序的正確性。實質(zhì)上,遵循這個原則可以確保繼承被謹慎地使用,并保持類層次結構的完整性。

例如:在數(shù)學中,正方形可以被歸類為矩形的一種特殊形式。它們之間的“是一個”關系可能會導致我們考慮在代碼中使用繼承來建模這種關系。然而,將正方形實現(xiàn)為矩形的派生類可能會導致意外的行為。

在數(shù)學中,正方形確實是矩形的一種特殊形式,正如“是一個”關系所暗示的那樣。這往往會引誘我們在代碼中使用繼承來建模這種關系。然而,將正方形實現(xiàn)為矩形的派生類可能會導致意想不到和違反直覺的行為。

我們用一個簡單的Java代碼示例來說明這個問題:

class Rectangle {
    protected int width;
    protected int height;

    public void setWidth(int width) {
        this.width = width;
    }

    public void setHeight(int height) {
        this.height = height;
    }

    public int calculateArea() {
        return width * height;
    }
}

class Square extends Rectangle {
    @Override
    public void setWidth(int width) {
        this.width = width;
        this.height = width; // 正方形的邊長始終相等,所以兩個維度都設置為相同的值。
    }

    @Override
    public void setHeight(int height) {
        this.height = height;
        this.width = height; // 正方形的邊長始終相等,所以兩個維度都設置為相同的值。
    }
}

public class Main {
    public static void main(String[] args) {
        Rectangle rectangle = new Square();
        rectangle.setWidth(5);
        rectangle.setHeight(3);

        System.out.println("Area: " + rectangle.calculateArea());
    }
}

在這個例子中,我們有一個基類Rectangle,其中包含setWidth和setHeight方法,分別用于設置矩形的寬度和高度。Square類繼承Rectangle類,并重寫這些方法,以確保兩個維度保持相等,以保持正方形的特性。

在主方法中,我們創(chuàng)建一個Rectangle引用,指向一個Square對象。當我們嘗試為寬度和高度設置不同的值(分別為5和3)時,我們得到了一個邊長為3的正方形,而不是實際寬度為5、高度為3的矩形。因此,計算得到的面積(9)與我們期望從寬度為5、高度為3的矩形得到的面積不符。

這個場景展示了里氏替換原則被違反的情況,通過Rectangle引用使用Square對象導致了意外的行為。

為了解決Square繼承Rectangle的問題,我們需要重新評估繼承關系和類設計。一種方法是在這種情況下避免使用繼承,而是專注于公共接口或組合。我們用Java代碼來說明解決方案:

interface Shape {
    int calculateArea();
}

class Rectangle implements Shape {
    protected int width;
    protected int height;

    public void setWidth(int width) {
        this.width = width;
    }

    public void setHeight(int height) {
        this.height = height;
    }

    @Override
    public int calculateArea() {
        return width * height;
    }
}

class Square implements Shape {
    protected int side;

    public void setSide(int side) {
        this.side = side;
    }

    @Override
    public int calculateArea() {
        return side * side;
    }
}

public class Main {
    public static void main(String[] args) {
        Shape rectangle = new Rectangle();
        rectangle.setWidth(5);
        rectangle.setHeight(3);
        System.out.println("矩形面積: " + rectangle.calculateArea());

        Shape square = new Square();
        square.setSide(5);
        System.out.println("正方形面積: " + square.calculateArea());
    }
}

在這個解決方案中,我們引入了一個名為Shape的公共接口,定義了calculateArea()方法。現(xiàn)在,Rectangle和Square都實現(xiàn)了這個接口。Rectangle類保留了setWidth和setHeight方法,而Square類有一個setSide方法。每個類根據(jù)自己特定的屬性計算面積。

現(xiàn)在,在main方法中,我們?yōu)镽ectangle和Square對象分別創(chuàng)建了不同的Shape引用。我們可以適當設置尺寸而不會遇到任何問題。

通過使用組合和共同接口,我們確保每個形狀都能獨立運作,并且按預期運行,而不違反里氏替換原則。這種設計使我們能夠優(yōu)雅地處理不同的形狀,促進了更清晰和可維護的代碼庫。

4. 接口隔離原則

接口隔離原則(ISP)建議客戶端不應被強迫依賴于它們不使用的接口。與其擁有龐大而笨重的接口,更好的做法是創(chuàng)建小而專注的接口,以滿足客戶端的特定需求。

讓我們通過一個簡單的Java代碼示例來說明ISP:

假設我們有一個名為Printer的接口,提供打印功能:

interface DocumentProcessor {
    void print();
    void fax();
}

class LaserPrinter implements DocumentProcessor {
    @Override
    public void print() {
        System.out.println("Printing with a laser printer.");
    }

    @Override
    public void fax() {
        System.out.println("Sending a fax with a laser printer.");
    }
}

class FaxMachine implements DocumentProcessor {
    @Override
    public void print() {
        // 傳真機無法打印,所以將這個方法保持為空。
    }

    @Override
    public void fax() {
        System.out.println("Sending a fax with a fax machine.");
    }
}

這個設計的問題在于FaxMachine類對于print()方法沒有有意義的實現(xiàn),因為傳真機無法打印文檔。盡管如此,F(xiàn)axMachine類仍然被強制實現(xiàn)print()方法,這是因為DocumentProcessor接口的設計。

這種對接口隔離原則的違反顯而易見,因為FaxMachine類現(xiàn)在需要實現(xiàn)它不需要或使用的方法。

5. 依賴反轉(zhuǎn)原則

SOLID原則的最后一塊拼圖是依賴反轉(zhuǎn)原則(Dependency Inversion Principle,DIP)。該原則主張高層模塊不應依賴于低層模塊,而應依賴于抽象。通過遵循這一原則,我們實現(xiàn)了解耦,從而增強了靈活性、可維護性和測試的便捷性。

讓我們通過一個小的Java代碼示例來說明違反依賴反轉(zhuǎn)原則的情況:

假設我們有一個ReportGenerator類,它直接依賴于一個DatabaseConnection類:

class DatabaseConnection {
    public void connect() {
        System.out.println("Connected to the database.");
    }

    public void executeQuery(String query) {
        System.out.println("Executing query: " + query);
    }

    public void close() {
        System.out.println("Connection closed.");
    }
}

class ReportGenerator {
    private DatabaseConnection databaseConnection;

    public ReportGenerator() {
        this.databaseConnection = new DatabaseConnection();
    }

    public void generateReport() {
        databaseConnection.connect();
        databaseConnection.executeQuery("SELECT * FROM data_table");
        databaseConnection.close();
        System.out.println("Report generated successfully.");
    }
}

在這段代碼中,ReportGenerator類在其構造函數(shù)中直接創(chuàng)建了一個DatabaseConnection實例。結果,ReportGenerator與DatabaseConnection緊密耦合。對DatabaseConnection類的任何更改都可能會影響到ReportGenerator。

為了解決這個問題,我們需要應用依賴反轉(zhuǎn)原則,引入一個兩個類都依賴的接口:

interface Connection {
    void connect();
    void executeQuery(String query);
    void close();
}

class DatabaseConnection implements Connection {
    @Override
    public void connect() {
        System.out.println("Connected to the database.");
    }

    @Override
    public void executeQuery(String query) {
        System.out.println("Executing query: " + query);
    }

    @Override
    public void close() {
        System.out.println("Connection closed.");
    }
}

class ReportGenerator {
    private Connection connection;

    public ReportGenerator(Connection connection) {
        this.connection = connection;
    }

    public void generateReport() {
        connection.connect();
        connection.executeQuery("SELECT * FROM data_table");
        connection.close();
        System.out.println("Report generated successfully.");
    }
}

public class Main {
    public static void main(String[] args) {
        Connection databaseConnection = new DatabaseConnection();
        ReportGenerator reportGenerator = new ReportGenerator(databaseConnection);

        reportGenerator.generateReport();
    }
}

通過遵循依賴反轉(zhuǎn)原則,我們通過Connection接口解耦了ReportGenerator和DatabaseConnection類。這種方法允許我們在不修改ReportGenerator的情況下輕松切換和擴展Connection接口的實現(xiàn)。現(xiàn)在的代碼符合原則,更易于維護和靈活。

結論

SOLID原則是面向?qū)ο箢愒O計的基石,對于每個尋求創(chuàng)建高效、可維護和協(xié)作的軟件的開發(fā)人員來說至關重要。當你踏上編碼之旅時,請記住SOLID運用原則!

責任編輯:趙寧寧 來源: Java學研大本營
相關推薦

2024-06-19 10:08:34

GoChannel工具

2010-08-04 14:32:33

求職

2015-08-17 16:05:35

javascript對象編程

2020-07-10 07:58:14

Linux

2023-12-26 12:10:13

2024-01-10 18:01:22

編程技巧Java 12

2024-11-15 11:11:48

2024-01-03 07:56:50

2022-05-18 09:01:19

JSONJavaScript

2018-10-26 14:10:21

2023-04-20 14:31:20

Python開發(fā)教程

2023-05-08 15:25:19

Python編程語言編碼技巧

2022-08-19 10:31:32

Kafka大數(shù)據(jù)

2024-07-26 08:32:44

panic?Go語言

2023-10-19 21:30:36

架構CQRS模式

2021-01-20 15:43:01

機器學習深度學習科學

2015-10-20 09:46:33

HTTP網(wǎng)絡協(xié)議

2019-01-30 14:14:16

LinuxUNIX操作系統(tǒng)

2020-08-23 18:18:27

Python列表數(shù)據(jù)結構

2021-06-09 11:06:00

數(shù)據(jù)分析Excel
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 国产精品美女久久久久久久网站 | 国产日韩精品在线 | 国产精品一区二区三区四区 | 99久久免费精品国产男女高不卡 | 精品久久国产 | 亚洲精品电影网在线观看 | 午夜成人免费视频 | 黄色网址在线免费播放 | 精品久久久久久亚洲精品 | 羞羞涩涩在线观看 | 亚洲精品成人网 | 国产探花| 婷婷综合久久 | 成人欧美一区二区三区在线播放 | 99精品九九 | 日日操夜夜操天天操 | 在线观看中文字幕视频 | 国产精品久久久久久久久久久免费看 | 日韩欧美精品一区 | 日韩一区不卡 | 久久er精品 | 老头搡老女人毛片视频在线看 | 中文字幕在线观看av | 国产精品a久久久久 | av在线视 | 日本久久一区二区三区 | 久久网一区二区三区 | 一区二区三区视频在线 | 97国产一区二区精品久久呦 | 国产免费一区二区三区 | 久久精品亚洲 | 一区在线视频 | 亚洲h视频 | 国产在线高清 | 亚洲综合电影 | 日日综合 | 青青草国产在线观看 | 国产一区久久 | 日韩一区二区三区在线观看 | 国产sm主人调教女m视频 | 日本久久一区二区三区 |