solid设计原则_SOLID设计原则

本文详细介绍了SOLID设计原则,包括单一责任原则、开闭原则、里斯科夫的替代原则、接口隔离原则和依赖倒置原则。这些原则旨在帮助开发者设计出更可扩展、可理解和可维护的面向对象系统。文章通过Java代码示例阐述了每个原则的实际应用,有助于提高代码质量并降低维护成本。
摘要由CSDN通过智能技术生成
solid设计原则

solid设计原则

介绍:

Robert C. Martin定义了五项面向对象的设计原则:

  • 小号英格尔-责任原则
  • Ø笔封闭原则
  • 大号iskov的替换原则
  • 覆盖整个院落分离原则,并
  • d ependency倒置原则

这些共同被称为SOLID原则。 在设计面向对象的系统时,我们应该尽可能地遵循这些原则。 这些原则有助于我们设计一个更可扩展,可理解和可维护的系统。

随着应用程序规模的扩大,使用这些原则可以帮助我们节省很多工作。

单一责任原则:

顾名思义,“单一责任原则”(SRP)指出,每个类都必须完全做一件事。 换句话说,我们修改类的原因不应多于一个。

众所周知,大型系统通常具有数千个类。 如果对于任何新要求,需要涉及多个类,那么我们就有更多机会通过破坏另一种功能来引入错误。

单一责任原则为我们带来以下好处:

  • 更少的耦合:由于每个类都只会做一件事,因此依赖关系将大大减少
  • 易于测试:更少的测试用例可以覆盖整个系统,从而使代码更易于测试

我们系统的模型类通常始终遵循SRP原则。 可以这么说,我们需要修改系统中用户的状态,我们只需触摸User类:

 public class User {
 
    private int id;

    private String name;

    private List<Address> addresses;
    
    //constructors, getters, setters
 }

因此,它遵循SRP原则。

开闭原理:

开放式封闭原则指出,软件组件必须开放才能扩展,但必须封闭才能修改。 此处的目的是避免由于代码修改而破坏某些现有的工作功能,从而避免在系统中引入错误。 我们应该扩展现有的类以支持任何其他功能。

此规则适用于我们的系统中更稳定的类,这些类已通过测试阶段并且在生产中运行良好。 我们将希望避免破坏现有代码中的任何内容,因此我们应该扩展其支持的功能以满足新的需求。

假设我们的系统中有一个EventPlanner类,该类在生产服务器上长期运行良好:

 public class EventPlanner {
 
    private List<String> participants;

    private String organizer;
 
    public void planEvent() {

        System.out.println( "Planning a simple traditional event" );

        ...

    }
 
    ...
 }

但是现在,我们计划改为使用ThemeEventPlanner ,它将使用随机主题来计划事件,以使事件变得更加有趣。 与其直接跳入现有代码并添加逻辑以选择事件主题并使用它,不如扩展我们的生产稳定类:

 public class ThemeEventPlanner extends EventPlanner {

    private String theme;
 
    ...
 }

对于大型系统,确定类的所有用途并不是很简单。 因此,通过仅扩展功能,我们减少了处理系统未知数的机会。

里斯科夫的替代原则:

Liskov的“替换原理”说,派生类型必须能够完全替代其基本类型,而不改变现有行为。 因此,如果我们有两个类AB使得B扩展了A,那么我们应该能够在整个代码库中用B替换A而不影响系统的行为。

为了使我们能够做到这一点,子类的对象的行为必须与超类对象的行为完全相同。

该原则有助于我们避免类型之间的错误关系,因为它们可能导致意外的错误或副作用。

让我们看下面的例子:

 public class Bird {

    public void fly() {

        System.out.println( "Bird is now flying" );

    }
 }
 public class Ostrich extends Bird {
    @Override

    public void fly() {

       throw new IllegalStateException( "Ostrich can't fly" );

    }
 }

尽管鸵鸟,但它仍然不能飞行,因此这明显违反了Liskov替代原理(LSP)。 同样,涉及类型检查逻辑的代码清楚地表明已建立了不正确的关系。

重构代码以遵循LSP有两种方法:

  • 消除对象之间的错误关系
  • 使用“告诉,不要问”原则消除类型检查和转换

假设我们有一些涉及类型检查的代码:

 //main method code
 for (User user : listOfUsers) {

    if (user SubscribedUser) { (user instanceof SubscribedUser) {

        user.offerDiscounts();

    }

    user.makePurchases();
 }

使用“告诉,不要问”的原则,我们将重构上面的代码,使其看起来像:

 public class SubscribedUser extends User {

    @Override

    public void makePurchases() {

        this .offerDiscounts();

        super .makePurchases();

    }
 
    public void offerDiscounts() {...}
 }
 //main method code for (User user : listOfUsers) {

    user.makePurchases();
 }

接口隔离原理:

根据接口隔离原则,不应强迫客户端处理他们不使用的方法。 我们应该在需要时将较大的接口拆分为较小的接口。

假设我们有一个ShoppingCart界面:

 public interface ShoppingCart {
 
    void addItem(Item item);

    void removeItem(Item item);

    void makePayment();

    boolean checkItemAvailability(Item item);
   }

付款和检查商品的可用性不是购物车要执行的操作。 我们很可能会遇到不使用这些方法的该接口的实现。

因此,最好将上述接口改为:

 public interface BaseShoppingCart {

    void addItem(Item item);

    void removeItem(Item item);
 }
 public interface PaymentProcessor {
    void makePayment();
 }
 public interface StockVerifier {
    boolean checkItemAvailability(Item item);
 }

接口隔离原则(ISP)还加强了其他原则:

  • 单一职责原则:实现较小接口的类通常更加集中并且通常具有单一目的
  • Liskov替换原理:使用较小的接口,我们有更多的机会让类实现它们以完全替代接口

依赖倒置:

它是最流行和有用的设计原则之一,因为它促进了对象之间的松散耦合。 依赖倒置原则指出高级模块不应该依赖于低级模块; 两者都应取决于抽象。

高级模块告诉我们该软件应该做什么。 用户授权和付款是高级模块的示例。

另一方面,低级模块告诉我们该软件应如何执行各种任务,即它涉及实现细节。 低级模块的一些示例包括安全性(OAuth),网络,数据库访问,IO等。

让我们编写一个UserRepository接口及其实现类:

 public interface UserRepository {

    List<User> findAllUsers();
 }
 public class UserRepository implements UserRepository {
 
    public List<User> findAllUsers() {

        //queries database and returns a list of users

        ...

    }
 }

我们在这里提取了接口中模块的抽象。

现在说我们有高级模块UserAuthorization ,它检查用户是否被授权访问系统。 我们将仅使用UserRepository接口的引用:

 public class UserAuthorization {
 
    ...
 
    public boolean isValidUser(User user) {

        UserRepository repo = UserRepositoryFactory.create();

        return repo.getAllUsers().stream().anyMatch(u -> u.equals(user));

    }
 }

另外,我们使用工厂类来实例化UserRepository

请注意,我们仅依靠抽象而不是依赖。 因此,我们可以轻松添加UserRepository的更多实现,而对我们的高级模块没有太大影响。

多么优雅!

结论:

在本教程中,我们讨论了SOLID设计原则。 我们还查看了上述每种原则的Java代码示例。

翻译自: https://www.javacodegeeks.com/2019/09/solid-design-principles.html

solid设计原则

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值