设计模式应该遵循的原则(软件思想)

  1. 单一职责原则(Single Responsibility Principle,SRP)

    • 定义:一个类应该只有一个引起它变化的原因。也就是说,一个类只负责一项职责。
    • 示例与解释:例如,有一个UserService类,它的职责如果包括用户的注册、登录以及用户信息的修改。这就不符合单一职责原则,因为用户注册和登录主要涉及认证相关的功能,而用户信息修改涉及数据更新的功能。更好的做法是将其拆分为UserAuthenticationService(负责用户认证相关功能)和UserInfoService(负责用户信息更新功能)两个类。这样,当认证相关的需求(如添加新的登录方式)发生变化时,只需要修改UserAuthenticationService类;当用户信息更新的规则(如添加新的信息字段)改变时,只需要修改UserInfoService类,而不会相互影响。
    • 优点:降低类的复杂度,提高类的可读性和可维护性,并且更容易进行单元测试,因为每个类的职责明确,测试用例的编写和维护也更加简单。
  2. 开闭原则(Open - Closed Principle,OCP)

    • 定义:软件实体(类、模块、函数等)应该对扩展开放,对修改关闭。即当需要对一个软件实体进行功能扩展时,应该通过扩展新的代码来实现,而不是修改原有的代码。
    • 示例与解释:以图形绘制系统为例,有一个Shape抽象类,它有draw方法,并且有CircleRectangle等具体形状类实现了这个方法来绘制自己的形状。如果要添加一个新的形状(如Triangle),应该是创建一个新的Triangle类来实现Shape类的draw方法,而不是修改Shape类或者已有的CircleRectangle类的draw方法。这样,在不修改原有代码的基础上,通过添加新的类就实现了功能的扩展,符合开闭原则。
    • 优点:使得软件系统具有更好的可扩展性和可维护性。当软件系统需要增加新功能时,不需要担心修改原有代码可能带来的风险,如引入新的错误或者影响已有的功能。
  3. 里氏替换原则(Liskov Substitution Principle,LSP)

    • 定义:所有引用基类(父类)的地方必须能透明地使用其子类的对象。也就是说,子类对象能够替换父类对象,并且程序的行为不会发生改变。
    • 示例与解释:假设有一个Animal基类,有一个makeSound方法,DogCatAnimal的子类。在一个函数printAnimalSound(Animal animal)中,它调用animal.makeSound()方法来打印动物的声音。根据里氏替换原则,DogCat类重写makeSound方法后,在printAnimalSound函数中,无论是传入Dog对象还是Cat对象,函数都应该能够正常工作,并且输出符合预期的动物叫声。如果Dog类重写makeSound方法后,执行的不是打印狗叫的声音,而是做了其他事情,就违反了里氏替换原则。
    • 优点:保证了继承关系的正确性和一致性,使得代码在使用多态性时能够按照预期工作,增强了程序的健壮性和可维护性。
  4. 依赖倒置原则(Dependency Inversion Principle,DIP)

    • 定义:高层模块不应该依赖低层模块,二者都应该依赖其抽象;抽象不应该依赖细节,细节应该依赖抽象。
    • 示例与解释:在一个简单的用户数据存储系统中,有一个UserRepository接口作为抽象,它定义了存储用户数据的基本方法(如saveUsergetUser等)。有MySQLUserRepositoryMongoDBUserRepository两个具体实现类,分别用于将用户数据存储到MySQL数据库和MongoDB数据库。高层模块(如UserService)应该依赖UserRepository这个抽象,而不是直接依赖MySQLUserRepository或者MongoDBUserRepository这些细节。这样,当需要更换数据库或者添加新的数据库存储方式时,只需要创建新的实现UserRepository接口的类,而不会影响到UserService这个高层模块。
    • 优点:降低了模块之间的耦合度,使得系统更加灵活和易于维护,便于进行单元测试和模块替换。
  5. 接口隔离原则(Interface Segregation Principle,ISP)

    • 定义:客户端不应该依赖它不需要的接口;一个类对另一个类的依赖应该建立在最小的接口上。
    • 示例与解释:假设有一个Worker接口,它定义了doWorktakeBreakattendMeeting等方法。但对于一些只负责实际工作的工人(如生产线上的工人),他们不需要attendMeeting这个功能。更好的做法是将Worker接口拆分为ProductiveWorker接口(包含doWorktakeBreak方法)和ManagerialWorker接口(包含attendMeeting等管理相关方法)。这样,生产线上的工人只需要实现ProductiveWorker接口,避免了实现不需要的attendMeeting方法,降低了类与接口之间的耦合度。
    • 优点:提高了接口的内聚性,减少了客户端需要实现的不必要的方法,使得接口的使用更加灵活和易于维护。
  6. 迪米特法则(Law of Demeter,LoD),也称为最少知识原则(Least Knowledge Principle)

    • 定义:一个对象应该对其他对象有最少的了解。也就是说,一个类应该尽量减少对其他类的依赖,只和与自己有直接关系的类进行交互。
    • 示例与解释:例如,有一个Order类,它包含Customer信息和Product信息。如果Order类需要计算订单总价,不应该直接访问Product类中的供应商信息来获取产品成本等数据来计算价格,因为Order类和供应商信息没有直接关系。应该是Product类提供一个获取产品价格的方法,Order类通过调用这个方法来获取产品价格,然后计算总价。这样就限制了Order类对其他类的了解范围,符合迪米特法则。
    • 优点:降低了类之间的耦合度,使得系统的维护和扩展更加容易,因为一个类的变化对其他类的影响范围更小。
  7. 组合/聚合复用原则(Composite/Aggregation Reuse Principle,CARP)

    • 定义:尽量使用组合(has - a关系)或聚合(owns - a关系)关系来实现复用,而不是使用继承关系。
    • 示例与解释:假设有一个Car类,它需要有一个导航系统的功能。可以通过继承一个NavigationSystem类来实现,但这会导致Car类和NavigationSystem类的耦合度很高。更好的做法是将NavigationSystem作为Car类的一个成员变量(组合关系),这样Car类可以使用NavigationSystem的功能,而且当NavigationSystem类发生变化时,不会像继承关系那样直接影响Car类。如果有多个类需要导航系统功能,也可以通过这种组合方式复用NavigationSystem,而不会像继承那样产生复杂的类层次结构。
    • 优点:使得系统更加灵活,降低了类之间的耦合度,并且可以在运行时动态地改变组合或聚合对象的行为,有利于代码的复用和维护。

人工智能写的比我好

posted @   Eular  阅读(65)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通
点击右上角即可分享
微信分享提示