第一句子网 - 唯美句子、句子迷、好句子大全
第一句子网 > solid设计原则_SOLID设计原则

solid设计原则_SOLID设计原则

时间:2019-05-27 23:20:29

相关推荐

solid设计原则_SOLID设计原则

solid设计原则

介绍:

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

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

这些一起被普遍称为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的“替换原理”说,派生类型必须能够完全替代其基本类型,而不改变现有行为。因此,如果我们有两个类A和B使得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代码示例。

翻译自: //09/solid-design-principles.html

solid设计原则

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。