自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

精益求精!在 Spring Boot 應(yīng)用中應(yīng)用 SOLID 原則

開(kāi)發(fā) 前端
在本文中,我們首先討論了在Java應(yīng)用中應(yīng)用SOLID原則時(shí)的錯(cuò)誤,隨后檢查了相關(guān)示例,以查看這些問(wèn)題是如何修復(fù)的。

在軟件開(kāi)發(fā)中,面向?qū)ο笤O(shè)計(jì)對(duì)于創(chuàng)建可輕易修改、擴(kuò)展和重復(fù)使用的代碼至關(guān)重要。

SOLID原則是一組在面向?qū)ο缶幊毯蛙浖_(kāi)發(fā)中的五個(gè)設(shè)計(jì)原則,旨在創(chuàng)建更易維護(hù)、靈活和可擴(kuò)展的軟件。這些原則由Robert C. Martin提出,廣泛作為設(shè)計(jì)清晰高效代碼的指導(dǎo)方針?!癝OLID”一詞中的每個(gè)字母代表一個(gè)原則:

  1. 單一責(zé)任原則(SRP)
  2. 開(kāi)放/封閉原則(OCP)
  3. 里氏替換原則(LSP)
  4. 接口隔離原則(ISP)
  5. 依賴反轉(zhuǎn)原則(DIP)

在本文中,我們將深入探討這些原則在Spring Boot應(yīng)用中的使用。

單一責(zé)任原則(SRP)

Robert C. Martin描述道:

一個(gè)類應(yīng)該有且僅有一個(gè)理由去改變。

單一責(zé)任原則有兩個(gè)關(guān)鍵點(diǎn),如其名所示。

讓我們看看下面的錯(cuò)誤用法示例。

@RestController
@RequestMapping("/report")
public class ReportController {
    private final ReportService reportService;

    public ReportController(ReportService reportService) {
        this.reportService = reportService;
    }

    @PostMapping("/send")
    public ResponseEntity<Report> generateAndSendReport(@RequestParam String reportContent,
                                                        @RequestParam String to,
                                                        @RequestParam String subject) {
        String report = reportService.generateReport(reportContent);
        reportService.sendReportByEmail(report, to, subject);
        return new ResponseEntity<>(HttpStatus.OK);
    }
}

// 錯(cuò)誤實(shí)現(xiàn)
@Service
@Slf4j
public class ReportServiceImpl implements ReportService {
    private final ReportRepository reportRepository;

    public ReportServiceImpl(ReportRepository reportRepository) {
        this.reportRepository = reportRepository;
    }

    @Override
    public String generateReport(String reportContent) {
        Report report = new Report();
        report.setReportContent(reportContent);
        return reportRepository.save(report).toString(); // 返回報(bào)告的字符串表示
    }

    @Override
    public void sendReportByEmail(Long reportId, String to, String subject) {
        Report report = findReportById(reportId);
        sendEmail(report.getReportContent(), to, subject);
    }

    private Report findReportById(Long reportId) {
        return reportRepository.findById(reportId)
                .orElseThrow(() -> new RuntimeException("未找到報(bào)告")); // 修改為中文錯(cuò)誤信息
    }

    private void sendEmail(String content, String to, String subject) {
       log.info(content, to, subject);
    }
}

如您所見(jiàn),ReportService有多個(gè)責(zé)任,違反了單一責(zé)任原則:

  • 生成報(bào)告:負(fù)責(zé)在generateReport方法中生成報(bào)告并將其保存到倉(cāng)庫(kù)。
  • 通過(guò)電子郵件發(fā)送報(bào)告:在sendReportByEmail方法中也負(fù)責(zé)發(fā)送報(bào)告。

創(chuàng)建代碼時(shí),需要避免在一個(gè)地方放入過(guò)多任務(wù)——無(wú)論是類還是方法。

這使代碼復(fù)雜且難以處理,也使得進(jìn)行小修改變得棘手,因?yàn)樗鼈兛赡苡绊懘a的其他部分,導(dǎo)致即使是小更新也需要測(cè)試所有內(nèi)容。

讓我們糾正這個(gè)實(shí)現(xiàn);

為遵循SRP,這些責(zé)任被分離到不同的類中。

@RestController
@RequestMapping("/report")
public class ReportController {
    private final ReportService reportService;
    private final EmailService emailService;

    public ReportController(ReportService reportService, EmailService emailService) {
        this.reportService = reportService;
        this.emailService = emailService;
    }

    @PostMapping("/send")
    public ResponseEntity<Report> generateAndSendReport(@RequestParam String reportContent,
                                                        @RequestParam String to,
                                                        @RequestParam String subject) {
        Long reportId = Long.valueOf(reportService.generateReport(reportContent));
        emailService.sendReportByEmail(reportId, to, subject);
        return new ResponseEntity<>(HttpStatus.OK);
    }
}

@Service
public class ReportServiceImpl implements ReportService {
    private final ReportRepository reportRepository;

    public ReportServiceImpl(ReportRepository reportRepository) {
        this.reportRepository = reportRepository;
    }

    @Override
    public String generateReport(String reportContent) {
        Report report = new Report();
        report.setReportContent(reportContent);
        return reportRepository.save(report).toString(); // 返回報(bào)告的字符串表示
    }
}

@Service
public class EmailServiceImpl implements EmailService {
    private final ReportRepository reportRepository;

    public EmailServiceImpl(ReportRepository reportRepository) {
        this.reportRepository = reportRepository;
    }

    @Override
    public void sendReportByEmail(Long reportId, String to, String subject) {
        Report report = findReportById(reportId);
        if (ObjectUtils.isEmpty(report) || !StringUtils.hasLength(report.getReportContent())) {
            throw new RuntimeException("報(bào)告或報(bào)告內(nèi)容為空"); // 修改為中文錯(cuò)誤信息
        }
    }

    private Report findReportById(Long reportId) {
        return reportRepository.findById(reportId)
                .orElseThrow(() -> new RuntimeException("未找到報(bào)告")); // 修改為中文錯(cuò)誤信息
    }
}

重構(gòu)后的代碼包括以下更改:

  • ReportServiceImpl負(fù)責(zé)生成報(bào)告。
  • EmailServiceImpl負(fù)責(zé)通過(guò)電子郵件發(fā)送報(bào)告——這些報(bào)告由ReportServiceImpl生成。
  • ReportController管理生成和發(fā)送報(bào)告的過(guò)程,使用適當(dāng)?shù)姆?wù)。

開(kāi)放/封閉原則(OCP)

開(kāi)放-封閉原則表示一個(gè)類應(yīng)該對(duì)擴(kuò)展開(kāi)放,對(duì)修改封閉。這有助于避免在工作應(yīng)用中引入錯(cuò)誤。簡(jiǎn)單來(lái)說(shuō),這意味著您應(yīng)該能夠向類中添加新功能,而無(wú)需更改現(xiàn)有代碼。

讓我們看看下面的錯(cuò)誤用法示例。

public class ReportGeneratorService {
    public String generateReport(Report report) {
        if ("PDF".equals(report.getReportType())) {
            return "生成PDF報(bào)告"; // 修改為中文輸出
        } else if ("Excel".equals(report.getReportType())) {
            return "生成Excel報(bào)告"; // 修改為中文輸出
        } else {
            return "不支持的報(bào)告類型"; // 修改為中文輸出
        }
    }
}

在這個(gè)錯(cuò)誤實(shí)現(xiàn)中,ReportService的generateReport方法包含條件語(yǔ)句來(lái)檢查報(bào)告類型,并直接生成相應(yīng)的報(bào)告。這違反了開(kāi)放-封閉原則,因?yàn)槿绻胩砑訉?duì)新報(bào)告類型的支持,您需要修改這個(gè)類。

讓我們糾正這個(gè)實(shí)現(xiàn);

public interface ReportGenerator {
    String generateReport(Report report);
}

// 生成PDF報(bào)告的具體實(shí)現(xiàn)
@Component
public class PdfReportGenerator implements ReportGenerator {
    @Override
    public String generateReport(Report report) {
        return String.format("為%s生成PDF報(bào)告", report.getReportType()); // 修改為中文輸出
    }
}

// 生成Excel報(bào)告的具體實(shí)現(xiàn)
@Component
public class ExcelReportGenerator implements ReportGenerator {
    @Override
    public String generateReport(Report report) {
        return String.format("為%s生成Excel報(bào)告", report.getReportType()); // 修改為中文輸出
    }
}

// 遵循OCP的服務(wù)
@Service
public class ReportGeneratorService {
    private final Map<String, ReportGenerator> reportGenerators;

    @Autowired
    public ReportGeneratorService(List<ReportGenerator> generators) {
        this.reportGenerators = generators.stream()
                .collect(Collectors.toMap(generator -> generator.getClass().getSimpleName(), Function.identity()));
    }

    public String generateReport(Report report, String reportType) {
        return reportGenerators.getOrDefault(reportType, unsupportedReportGenerator())
                .generateReport(report);
    }

    private ReportGenerator unsupportedReportGenerator() {
        return report -> "不支持的報(bào)告類型"; // 修改為中文輸出
    }
}
  • 引入了ReportGenerator接口,定義了一個(gè)通用的方法來(lái)生成報(bào)告。
  • 創(chuàng)建了實(shí)現(xiàn)該接口的PdfReportGenerator和ExcelReportGenerator類。
  • 引入了ReportGeneratorService,管理不同的報(bào)告生成實(shí)現(xiàn),允許在不改變現(xiàn)有代碼的情況下添加新的報(bào)告生成器。

里氏替換原則(LSP)

里氏替換原則表示,如果您有一個(gè)類,您應(yīng)該能夠用一個(gè)子類替換它,而不會(huì)對(duì)程序造成任何問(wèn)題。換句話說(shuō),您可以在任何使用通用版本的地方使用特定版本,且一切仍然應(yīng)正常工作。

讓我們看看下面的錯(cuò)誤用法示例。

public class Bird {
    public void fly() {
        // 我會(huì)飛
    }

    public void swim() {
        // 我會(huì)游泳
    }
}

public class Penguin extends Bird {
    @Override
    public void fly() {
        throw new UnsupportedOperationException("企鵝不能飛"); // 修改為中文錯(cuò)誤信息
    }
}

讓我們糾正這個(gè)實(shí)現(xiàn);

public class Bird {
    // 方法
}

public interface Flyable {
    void fly(); // 飛
}

public interface Swimmable {
    void swim(); // 游泳
}

public class Penguin extends Bird implements Swimmable {
    @Override
    public void swim() {
        System.out.println("我會(huì)游泳");
    }
}

public class Eagle extends Bird implements Flyable {
    @Override
    public void fly() {
        System.out.println("我會(huì)飛");
    }
}

Bird類作為鳥類的基類,包含所有鳥類共享的通用屬性或方法。引入Flyable和Swimmable接口以表示特定行為。在Penguin類中,實(shí)現(xiàn)Swimmable接口以反映企鵝的游泳能力;在Eagle類中,實(shí)現(xiàn)Flyable接口以反映老鷹的飛行能力。通過(guò)將特定行為分離到接口中,并在子類中實(shí)現(xiàn)它們,我們遵循了里氏替換原則,允許我們?cè)诓灰鹨馔鈫?wèn)題的情況下切換子類。

接口隔離原則(ISP)

接口隔離原則指出,較大的接口應(yīng)拆分為較小的接口。這樣可以確保實(shí)現(xiàn)類只需關(guān)心對(duì)它們感興趣的方法。

讓我們看看下面的錯(cuò)誤用法示例。

public interface Athlete {
    void compete(); // 比賽
    void swim();    // 游泳
    void highJump(); // 跳高
    void longJump(); // 跳遠(yuǎn)
}

// 錯(cuò)誤實(shí)現(xiàn)違反接口隔離
public class JohnDoe implements Athlete {
    @Override
    public void compete() {
        System.out.println("路條小哥開(kāi)始比賽");
    }

    @Override
    public void swim() {
        System.out.println("路條小哥開(kāi)始游泳");
    }

    @Override
    public void highJump() {
        // 路條小哥來(lái)說(shuō)不必要
    }

    @Override
    public void longJump() {
        // 路條小哥來(lái)說(shuō)不必要
    }
}

假設(shè)John Doe是一名游泳運(yùn)動(dòng)員,他被迫提供高跳和長(zhǎng)跳的空實(shí)現(xiàn),這對(duì)他作為游泳運(yùn)動(dòng)員的角色無(wú)關(guān)緊要。

讓我們糾正這個(gè)實(shí)現(xiàn);

public interface Athlete {
    void compete(); // 比賽
}

public interface JumpingAthlete {
    void highJump(); // 跳高
    void longJump(); // 跳遠(yuǎn)
}

public interface SwimmingAthlete {
    void swim(); // 游泳
}

// 正確的接口隔離實(shí)現(xiàn)
public class JohnDoe implements Athlete, SwimmingAthlete {
    @Override
    public void compete() {
        System.out.println("路條小哥開(kāi)始比賽");
    }

    @Override
    public void swim() {
        System.out.println("路條小哥開(kāi)始游泳");
    }
}

原始的Athlete接口被拆分為三個(gè)獨(dú)立接口:Athlete用于一般活動(dòng),JumpingAthlete用于跳躍相關(guān)活動(dòng),SwimmingAthlete用于游泳。這遵循了接口隔離原則,確保一個(gè)類不被迫實(shí)現(xiàn)它不需要的方法。

依賴反轉(zhuǎn)原則(DIP)

依賴反轉(zhuǎn)原則(DIP)指出,高層模塊不應(yīng)依賴于低層模塊;兩者都應(yīng)依賴于抽象。抽象不應(yīng)依賴于細(xì)節(jié)。

讓我們看看下面的錯(cuò)誤用法示例。

@Service
public class PayPalPaymentService {
    public void processPayment(Order order) {
        // 支付處理邏輯
    }
}

@RestController
public class PaymentController {
    private final PayPalPaymentService paymentService;

    public PaymentController() {
        this.paymentService = new PayPalPaymentService();
    }

    @PostMapping("/pay")
    public void pay(@RequestBody Order order) {
        paymentService.processPayment(order);
    }
}

讓我們糾正這個(gè)實(shí)現(xiàn);

public interface PaymentService {
    void processPayment(Order order); // 處理支付
}

@Service
public class PayPalPaymentService implements PaymentService {
    @Override
    public void processPayment(Order order) {
        // 支付處理邏輯
    }
}

@RestController
public class PaymentController {
    private final PaymentService paymentService;

    public PaymentController(PaymentService paymentService) {
        this.paymentService = paymentService;
    }

    @PostMapping("/pay")
    public void pay(@RequestBody Order order) {
        paymentService.processPayment(order);
    }
}
  • 引入了PaymentService接口。
  • 在控制器的構(gòu)造函數(shù)中注入PaymentService接口,以提供控制器中的抽象??刂破饕蕾囉诔橄螅≒aymentService),允許注入任何實(shí)現(xiàn)該接口的類。

結(jié)論

SOLID原則在面向?qū)ο缶幊蹋∣OP)中至關(guān)重要,因?yàn)樗鼈兲峁┝艘唤M設(shè)計(jì)更易維護(hù)、靈活和可擴(kuò)展的軟件的指南和最佳實(shí)踐。在本文中,我們首先討論了在Java應(yīng)用中應(yīng)用SOLID原則時(shí)的錯(cuò)誤,隨后檢查了相關(guān)示例,以查看這些問(wèn)題是如何修復(fù)的。

責(zé)任編輯:武曉燕 來(lái)源: 路條編程
相關(guān)推薦

2022-07-15 09:01:15

React對(duì)象編程

2019-07-15 10:00:53

DockerJava容器

2019-07-15 16:00:24

Docker架構(gòu)容器

2024-10-07 08:40:56

Spring應(yīng)用程序Java

2017-09-20 09:46:38

Spring BootSpring Clou內(nèi)存

2018-10-07 23:03:22

數(shù)據(jù)應(yīng)用Web

2022-06-28 08:02:44

SPISpringJava

2017-10-24 15:28:27

PHP代碼簡(jiǎn)潔SOLID原則

2022-09-27 09:21:34

SOLID開(kāi)閉原則Go

2021-07-02 20:37:19

Python代碼SRP

2020-03-19 10:44:19

DockerSpring Boo單層鏡像

2016-10-14 14:16:28

Spring BootJava應(yīng)用

2018-10-22 15:34:31

Spring Boo監(jiān)控視化

2018-05-25 16:32:45

Spring BootJava開(kāi)發(fā)

2022-02-09 20:39:52

Actuator應(yīng)用監(jiān)控

2024-11-29 12:58:13

2024-12-03 10:59:36

2023-12-27 18:05:13

2023-12-08 12:12:21

2020-11-10 09:19:23

Spring BootJava開(kāi)發(fā)
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)