第一句子网 - 唯美句子、句子迷、好句子大全
第一句子网 > solid测序列原理_SOLID原理简介

solid测序列原理_SOLID原理简介

时间:2021-06-30 02:17:40

相关推荐

solid测序列原理_SOLID原理简介

solid测序列原理

Kriptofolio应用程序系列-第1部分 (Kriptofolio app series - Part 1)

Software is always in a state of change. Each change can have a negative impact on a whole project. So the essential thing is to prevent damage that can be done while implementing all new changes.

软件始终处于变化状态。 每次更改都会对整个项目产生负面影响。 因此,最重要的是防止在实施所有新更改时可能造成的损坏。

With “Kriptofolio” (previously “My Crypto Coins”) app, I will be creating a lot of new code step by step and I want to start doing that in a good way. I want my project to be solid quality. First we need to understand the foundation principles of creating modern software. They are called SOLID principles. Such a catchy name! 🙂

使用“ Kriptofolio”(以前称为“ My Crypto Coins”)应用程序,我将逐步创建许多新代码,我希望以一种很好的方式开始这样做。 我希望我的项目质量可靠。 首先,我们需要了解创建现代软件的基本原理。 它们被称为SOLID原理。 这么好听的名字! 🙂

系列内容 (Series content)

Introduction: A roadmap to build a modern Android app in –

简介:-构建现代Android应用程序的路线图

Part 1: An introduction to the SOLID principles (you’re here)第1部分:SOLID原理简介(您在这里)

Part 2: How to start building your Android app: creating Mockups, UI, and XML layouts

第2部分:如何开始构建Android应用:创建样机,UI和XML布局

Part 3: All about that Architecture: exploring different architecture patterns and how to use them in your app

第3部分:有关该架构的全部内容:探索不同的架构模式以及如何在您的应用程序中使用它们

Part 4: How to implement Dependency Injection in your app with Dagger 2

第4部分:如何使用Dagger 2在您的应用程序中实现依赖注入

Part 5: Handle RESTful Web Services using Retrofit, OkHttp, Gson, Glide and Coroutines

第5部分:使用Retrofit,OkHttp,Gson,Glide和Coroutines处理RESTful Web服务

原则口号 (Principles slogan)

SOLIDis a mnemonic acronym. It helps to define the five basic object-oriented design principles:

SOLID是助记符的缩写。 它有助于定义五项面向对象的基本设计原则:

Single Responsibility Principle

小号英格尔责任原则

Open-Closed Principle

Ø笔封闭原则

Liskov Substitution Principle

大号iskov替换原则

Interface Segregation Principle

覆盖整个院落分离原则

Dependency Inversion Principle

dependency倒置原则

Next we are going to discuss each of them individually. For each, I am going to provide bad vs good code examples. These examples are written for Android using the Kotlin language.

接下来,我们将分别讨论它们。 对于每一个,我将提供不好的代码示例和好的代码示例。 这些示例是使用Kotlin语言为Android编写的。

单一责任原则 (Single Responsibility Principle)

A class should have only a single responsibility.

一个班级应该只有一个责任。

Each class or module should be responsible for one part of the functionality provided by the app. So when it handles one thing, there should be only one main reason to change it. If your class or module does more than one thing, then you should split the functionalities in separate ones.

每个类或模块应负责应用提供的功能的一部分。 因此,当它处理一件事时,应该只有一个主要原因来更改它。 如果您的类或模块执行了多项操作,则应将功能拆分为单独的功能。

For a better understanding of this principle, I would take as an example a Swiss Army knife. This knife is well known for its multiple functions besides its main blade. It has other tools integrated inside, such as screwdrivers, a can opener, and many others.

为了更好地理解这一原理,我以瑞士军刀为例。 除主刀片外,这把刀还以其多功能而著称。 它内部还集成了其他工具,例如螺丝刀,开罐器等。

The natural question here for you is why am I suggesting this knife as an example for single functionality? But just think about it one moment. The other main feature of this knife is mobility while being pocket size. So even if it offers a few different functions it still fits its main purpose to be small enough to take it with you comfortably.

给您一个自然的问题是,为什么我建议将此刀作为单一功能的示例? 但是,想一想。 这把刀的另一个主要特点是口袋大小,同时又具有机动性。 因此,即使它提供了一些不同的功能,它仍然符合其主要目的,即足够小以舒适地随身携带。

The same rules go with programming. When you create your class or module, it has to have some main global purpose. At the same time you can’t overplay when trying to simplify everything too much by separating functionality. So remember, keep the balance.

编程遵循相同的规则。 创建类或模块时,它必须具有某些主要的全局用途。 同时,当试图通过分离功能来简化太多事情时,您也不会过分夸大。 所以请记住,保持平衡。

A classic example could be the often used methodonBindViewHolderwhen building RecyclerView widget adapter.

一个典型的例子是构建RecyclerView小部件适配器时常用的onBindViewHolder方法。

👿 BAD CODE EXAMPLE:

👿错误代码示例:

class MusicVinylRecordRecyclerViewAdapter(private val vinyls: List<VinylRecord>, private val itemLayout: Int) : RecyclerView.Adapter<MusicVinylRecordRecyclerViewAdapter.ViewHolder>() {...override fun onBindViewHolder(holder: ViewHolder, position: Int) {val vinyl = vinyls[position]holder.itemView.tag = vinylholder.title!!.text = vinyl.titleholder.author!!.text = vinyl.authorholder.releaseYear!!.text = vinyl.releaseYearholder.country!!.text = vinyl.countryholder.condition!!.text = vinyl.condition/*** Here method violates the Single Responsibility Principle!!!* Despite its main and only responsibility to be adapting a VinylRecord object* to its view representation, it is also performing data formatting as well.* It has multiple reasons to be changed in the future, which is wrong.*/var genreStr = ""for (genre in vinyl.genres!!) {genreStr += genre + ", "}genreStr = if (genreStr.isNotEmpty())genreStr.substring(0, genreStr.length - 2)elsegenreStrholder.genre!!.text = genreStr}...}

🙂 GOOD CODE EXAMPLE:

🙂良好代码示例:

class MusicVinylRecordRecyclerViewAdapter(private val vinyls: List<VinylRecord>, private val itemLayout: Int) : RecyclerView.Adapter<MusicVinylRecordRecyclerViewAdapter.ViewHolder>() {...override fun onBindViewHolder(holder: ViewHolder, position: Int) {val vinyl = vinyls[position]holder.itemView.tag = vinylholder.title!!.text = vinyl.titleholder.author!!.text = vinyl.authorholder.releaseYear!!.text = vinyl.releaseYearholder.country!!.text = vinyl.countryholder.condition!!.text = vinyl.condition/*** Instead of performing data formatting operations here, we move that responsibility to* other class. Actually here you see only direct call of top-level function* convertArrayListToString - new Kotlin language feature. However don't be mistaken,* because Kotlin compiler behind the scenes still is going to create a Java class, and* than the individual top-level functions will be converted to static methods. So single* responsibility for each class.*/holder.genre!!.text = convertArrayListToString(vinyl.genres)}...}

Code specifically designed with the Single Responsibility Principle in mind will be close to the other principles that we are going to discuss.

考虑到“单一责任原则”而专门设计的代码将与我们将要讨论的其他原则接近。

开闭原则 (Open-Closed Principle)

Software entities should be open for extension, but closed for modification.

软件实体应开放以进行扩展,但应封闭以进行修改。

This principle states that when you write all the software parts like classes, modules, and functions, you should make them open for extension but closed for any modification. What does that mean?

该原则指出,当编写所有软件部分(如类,模块和函数)时,应将其打开以进行扩展,但关闭以进行任何修改。 那是什么意思?

Let’s say we create a working class. There should be no need to tweak that class if we need to add new functionality or do some changes. Instead we should be able to extend that class by creating its new subclass where we could easily add all new necessary features. Features should always be parameterized in a way that a subclass can override.

假设我们创建了一个工人阶级。 如果我们需要添加新功能或进行一些更改,则无需调整该类。 相反,我们应该能够通过创建新的子类来扩展该类,在该子类中我们可以轻松添加所有新的必要功能。 应该始终以子类可以覆盖的方式对要素进行参数化。

Let’s take a look at an example where we will create a specialFeedbackManagerclass to show a different type of custom message for the user.

让我们看一个示例,在该示例中,我们将创建一个特殊的FeedbackManager类,以为用户显示不同类型的自定义消息。

👿 BAD CODE EXAMPLE:

👿错误代码示例:

class MainActivity : AppCompatActivity() {lateinit var feedbackManager: FeedbackManageroverride fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)setContentView(R.layout.activity_main)feedbackManager = FeedbackManager(findViewById(android.R.id.content));}override fun onStart() {super.onStart()feedbackManager.showToast(CustomToast())}}class FeedbackManager(var view: View) {// Imagine that we need to add new type feedback message. What would happen?// We would need to modify this manager class. But to follow Open Closed Principle we// need to write a code that can be adapted automatically to the new requirements without// rewriting the old classes.fun showToast(customToast: CustomToast) {Toast.makeText(view.context, customToast.welcomeText, customToast.welcomeDuration).show()}fun showSnackbar(customSnackbar: CustomSnackbar) {Snackbar.make(view, customSnackbar.goodbyeText, customSnackbar.goodbyeDuration).show()}}class CustomToast {var welcomeText: String = "Hello, this is toast message!"var welcomeDuration: Int = Toast.LENGTH_SHORT}class CustomSnackbar {var goodbyeText: String = "Goodbye, this is snackbar message.."var goodbyeDuration: Int = Toast.LENGTH_LONG}

🙂 GOOD CODE EXAMPLE:

OD良好代码示例:

class MainActivity : AppCompatActivity() {lateinit var feedbackManager: FeedbackManageroverride fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)setContentView(R.layout.activity_main)feedbackManager = FeedbackManager(findViewById(android.R.id.content));}override fun onStart() {super.onStart()feedbackManager.showSpecialMessage(CustomToast())}}class FeedbackManager(var view: View) {// Again the same situation - we need to add new type feedback message. We have to write code// that can be adapted to new requirements without changing the old class implementation.// Here the solution is to focus on extending the functionality by using interfaces and it// follows the Open Closed Principle.fun showSpecialMessage(message: Message) {message.showMessage(view)}}interface Message {fun showMessage(view: View)}class CustomToast: Message {var welcomeText: String = "Hello, this is toast message!"var welcomeDuration: Int = Toast.LENGTH_SHORToverride fun showMessage(view: View) {Toast.makeText(view.context, welcomeText, welcomeDuration).show()}}class CustomSnackbar: Message {var goodbyeText: String = "Goodbye, this is snackbar message.."var goodbyeDuration: Int = Toast.LENGTH_LONGoverride fun showMessage(view: View) {Snackbar.make(view, goodbyeText, goodbyeDuration).show()}}

The open-closed principle summarizes the goals of the next two principles that I talk about below. So let’s move on to them.

开闭原则总结了下面我要讨论的下两个原则的目标。 因此,让我们继续前进。

里斯科夫替代原则 (Liskov Substitution Principle)

Objects in a program should be replaceable with instances of their subtypes without altering the correctness of that program.

程序中的对象应该可以用其子类型的实例替换,而不会改变该程序的正确性。

This principle is named after Barbara Liskov — an accomplished computer scientist. The general idea of this principle is that objects should be replaceable by instances of their subtypes without changing the behavior of the program.

这项原则以一位杰出的计算机科学家Barbara Liskov的名字命名。 该原理的总体思想是,对象应可被其子类型的实例替换,而无需更改程序的行为。

Let’s say in your app you haveMainClasswhich depends onBaseClass, which extendsSubClass. In short, to follow this principle, yourMainClasscode and your app in general should work seamlessly without any problems when you decide to changeBaseClassinstance to theSubClassinstance.

假设您的应用中有MainClass,它依赖于BaseClass,后者扩展了SubClass。 简而言之,要遵循这一原则,当您决定将BaseClass实例更改为SubClass实例时,MainClass代码和您的应用程序通常应该可以无缝运行。

To understand this principle even better, let me give you a classical, easy to understand example withSquareandRectangleinheritance.

为了更好地理解该原理,让我给您一个经典的,易于理解的带有SquareRectangle继承的示例。

👿 BAD CODE EXAMPLE:

👿错误代码示例:

class MainActivity : AppCompatActivity() {override fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)setContentView(R.layout.activity_main)val rectangleFirst: Rectangle = Rectangle()rectangleFirst.width = 2rectangleFirst.height = 3textViewRectangleFirst.text = rectangleFirst.area().toString()// The result of the first rectangle area is 6, which is correct as 2 x 3 = 6.// The Liskov Substitution Principle states that a subclass (Square) should override// the parent class (Rectangle) in a way that does not break functionality from a// consumers’s point of view. Let's see.val rectangleSecond: Rectangle = Square()// The user assumes that it is a rectangle and try to set the width and the height as usualrectangleSecond.width = 2rectangleSecond.height = 3textViewRectangleSecond.text = rectangleSecond.area().toString()// The expected result of the second rectangle should be 6 again, but instead it is 9.// So as you see this object oriented approach for Square extending Rectangle is wrong.}}open class Rectangle {open var width: Int = 0open var height: Int = 0open fun area(): Int {return width * height}}class Square : Rectangle() {override var width: Intget() = super.widthset(width) {super.width = widthsuper.height = width}override var height: Intget() = super.heightset(height) {super.width = heightsuper.height = height}}

🙂 GOOD CODE EXAMPLE:

OD良好代码示例:

class MainActivity : AppCompatActivity() {override fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)setContentView(R.layout.activity_main)// Here it is presented a way how to organize these Rectangle and Square classes better to// meet the Liskov Substitution Principle. No more unexpected result.val rectangleFirst: Shape = Rectangle(2,3)val rectangleSecond: Shape = Square(3)textViewRectangleFirst.text = rectangleFirst.area().toString()textViewRectangleSecond.text = rectangleSecond.area().toString()}}class Rectangle(var width: Int, var height: Int) : Shape() {override fun area(): Int {return width * height}}class Square(var edge: Int) : Shape() {override fun area(): Int {return edge * edge}}abstract class Shape {abstract fun area(): Int}

Always think before writing down your hierarchy. As you see in this example, real-life objects do not always map to the same OOP classes. You need to find a different approach.

在写下您的层次结构之前,请务必三思。 如本例所示,现实生活中的对象并不总是映射到相同的OOP类。 您需要找到其他方法。

接口隔离原理 (Interface Segregation Principle)

Many client-specific interfaces are better than one general-purpose interface.

许多特定于客户端的接口比一个通用接口要好。

Even the name sounds complicated, but the principle itself is rather easy to understand. It states that a client should never be forced to depend on methods or implement an interface that it doesn’t use. A class needs to be designed to have the fewest methods and attributes. When creating an interface try not to make it too big. Instead split it into smaller interfaces so that client of the interface will only know about the methods that are relevant.

即使名称听起来很复杂,但原理本身也很容易理解。 它指出,永远不要强迫客户端依赖于不使用的方法或实现其不使用的接口。 需要将一个类设计为具有最少的方法和属性。 创建接口时,请尽量不要使其过大。 而是将其拆分为较小的接口,以便该接口的客户端仅知道相关的方法。

To get the idea of this principle I have created again bad vs good code examples with butterfly and humanoid robots. 😉

为了理解这一原理,我再次使用蝴蝶机器人和类人机器人创建了不好的代码示例。 😉

👿 BAD CODE EXAMPLE:

👿错误代码示例:

/*** Let's imagine we are creating some undefined robot. We decide to create an interface with all* possible functions to it.*/interface Robot {fun giveName(newName: String)fun reset()fun fly()fun talk()}/*** First we are creating butterfly robot which implements that interface.*/class ButterflyRobot : Robot {var name: String = ""override fun giveName(newName: String) {name = newName}override fun reset() {// Calls reset command for the robot. Any robot's software should be possible to reset.// That is reasonable and we will implement this.TODO("not implemented")}override fun fly() {// Calls fly command for the robot. This is specific functionality of our butterfly robot.// We will definitely implement this.TODO("not implemented")}override fun talk() {// Calls talk command for the robot.// WRONG!!! Our butterfly robot is not going to talk, just fly! Why we need implement this?// Here it is a violation of Interface Segregation Principle as we are forced to implement// a method that we are not going to use.TODO("???")}}/*** Next we are creating humanoid robot which should be able to do similar actions as human and it* also implements same interface.*/class HumanoidRobot : Robot {var name: String = ""override fun giveName(newName: String) {name = newName}override fun reset() {// Calls reset command for the robot. Any robot's software should be possible to reset.// That is reasonable and we will implement this.TODO("not implemented")}override fun fly() {// Calls fly command for the robot.// That the problem! We have never had any intentions for our humanoid robot to fly.// Here it is a violation of Interface Segregation Principle as we are forced to implement// a method that we are not going to use.TODO("???")}override fun talk() {// Calls talk command for the robot. This is specific functionality of our humanoid robot.// We will definitely implement this.TODO("not implemented")}}

🙂 GOOD CODE EXAMPLE:

🙂良好代码示例:

/*** Let's imagine we are creating some undefined robot. We should create a generic interface with all* possible functions common to all types of robots.*/interface Robot {fun giveName(newName: String)fun reset()}/*** Specific robots which can fly should have their own interface defined.*/interface Flyable {fun fly()}/*** Specific robots which can talk should have their own interface defined.*/interface Talkable {fun talk()}/*** First we are creating butterfly robot which implements a generic interface and a specific one.* As you see we are not required anymore to implement functions which are not related to our robot!*/class ButterflyRobot : Robot, Flyable {var name: String = ""override fun giveName(newName: String) {name = newName}override fun reset() {// Calls reset command for the robot. Any robot's software should be possible to reset.// That is reasonable and we will implement this.TODO("not implemented")}// Calls fly command for the robot. This is specific functionality of our butterfly robot.// We will definitely implement this.override fun fly() {TODO("not implemented")}}/*** Next we are creating humanoid robot which should be able to do similar actions as human and it* also implements generic interface and specific one for it's type.* As you see we are not required anymore to implement functions which are not related to our robot!*/class HumanoidRobot : Robot, Talkable {var name: String = ""override fun giveName(newName: String) {name = newName}override fun reset() {// Calls reset command for the robot. Any robot's software should be possible to reset.// That is reasonable and we will implement this.TODO("not implemented")}override fun talk() {// Calls talk command for the robot. This is specific functionality of our humanoid robot.// We will definitely implement this.TODO("not implemented")}}

依赖倒置原则 (Dependency Inversion Principle)

One should “depend upon abstractions, [not] concretions.”

一个人应该“取决于抽象,而不是具体的东西”。

The last principle states that high-level modules should not depend on low-level modules. Both should depend on abstractions. Abstractions should not depend on details. Details should depend on abstractions.

最后一条原则指出,高级模块不应依赖于低级模块。 两者都应依赖抽象。 抽象不应依赖细节。 细节应取决于抽象。

The main idea of the principle is not to have direct dependencies between the modules and classes. Try to make them dependent on the abstractions (e.g. interfaces) instead.

该原理的主要思想是在模块和类之间不具有直接依赖关系。 尝试使它们依赖于抽象(例如接口)。

To simplify it even more, if you use a class inside another class, this class will be dependent on the class injected. This violates the principle’s idea and you should not do that. You should try to decouple all classes.

为了进一步简化,如果在另一个类中使用一个类,则该类将依赖于注入的类。 这违反了原则的想法,您不应这样做。 您应该尝试分离所有类。

👿 BAD CODE EXAMPLE:

👿错误代码示例:

class Radiator {var temperatureCelsius : Int = 0fun turnOnHeating(newTemperatureCelsius : Int) {temperatureCelsius = newTemperatureCelsius// To turn on heating for the radiator we will have to do specific steps for this device.// Radiator will have it's own technical procedure of how it will be turned on.// Procedure implemented here.TODO("not implemented")}}class AirConditioner {var temperatureFahrenheit: Int = 0fun turnOnHeating(newTemperatureFahrenheit: Int) {temperatureFahrenheit = newTemperatureFahrenheit// To turn on heating for air conditioner we will have to do some specific steps// just for this device, as air conditioner will have it's own technical procedure.// This procedure is different compared to radiator and will be implemented here.TODO("not implemented")}}class SmartHome {// To our smart home control system we added a radiator control.var radiator: Radiator = Radiator()// But what will be if later we decide to change our radiator to air conditioner instead?// var airConditioner: AirConditioner = AirConditioner()// This SmartHome class is dependent of the class Radiator and violates Dependency Inversion Principle.var recommendedTemperatureCelsius : Int = 20fun warmUpRoom() {radiator.turnOnHeating(recommendedTemperatureCelsius)// If we decide to ignore the principle there may occur some important mistakes, like this// one. Here we pass recommended temperature in celsius but our air conditioner expects to// get it in Fahrenheit.// airConditioner.turnOnHeating(recommendedTemperatureCelsius)}}

🙂 GOOD CODE EXAMPLE:

OD良好代码示例:

// First let's create an abstraction - interface.interface Heating {fun turnOnHeating(newTemperatureCelsius : Int)}// Class should implement the Heating interface.class Radiator : Heating {var temperatureCelsius : Int = 0override fun turnOnHeating(newTemperatureCelsius: Int) {temperatureCelsius = newTemperatureCelsius// Here radiator will have it's own technical procedure implemented of how it will be turned on.TODO("not implemented")}}// Class should implement the Heating interface.class AirConditioner : Heating {var temperatureFahrenheit: Int = 0override fun turnOnHeating(newTemperatureCelsius: Int) {temperatureFahrenheit = newTemperatureCelsius * 9/5 + 32// Air conditioner's turning on technical procedure will be implemented here.TODO("not implemented")}}class SmartHome {// To our smart home control system we added a radiator control.var radiator: Heating = Radiator()// Now we have an answer to the question what will be if later we decide to change our radiator// to air conditioner. Our class is going to depend on the interface instead of another// injected class.// var airConditioner: Heating = AirConditioner()var recommendedTemperatureCelsius : Int = 20fun warmUpRoom() {radiator.turnOnHeating(recommendedTemperatureCelsius)// As we depend on the common interface, there is no more chance for mistakes.// airConditioner.turnOnHeating(recommendedTemperatureCelsius)}}

总结一下 (To sum up briefly)

If we think about all these principles, we can notice that they are complementary to each other. Following the SOLID principles will give us many benefits. They will make our app reusable, maintainable, scalable, testable.

如果我们考虑所有这些原则,就会发现它们是相互补充的。 遵循SOLID原则将为我们带来很多好处。 它们将使我们的应用程序可重用,可维护,可扩展,可测试。

Of course it is not always possible to follow all these principles completely, as everything depends on individual situations when writing code. But as a developer you should at least know them so you can decide when to apply them.

当然,并非总是可以完全遵循所有这些原则,因为编写代码时一切都取决于个别情况。 但是作为开发人员,您至少应该了解它们,以便您决定何时应用它们。

资料库 (Repository)

This is the first part where we learn and plan our project instead of writing new code. Here is a link to Part 1 branch commit, which basically is “Hello world” initial code of the project.

这是我们学习和计划项目的第一部分,而不是编写新代码。 这里是第1部分分支提交的链接,基本上是项目的“ Hello world”初始代码。

在GitHub上查看源代码 (View Source On GitHub)

I hope I managed to explain SOLID principles well. Feel free to leave comments below.

我希望我能很好地解释SOLID原则。 随时在下面发表评论。

Ačiū! Thanks for reading! I originally published this post for my personal blog on February 23, .

阿奇!谢谢阅读!我最初于2月23日在我的个人博客上发布了这篇文章。

翻译自: /news/kriptofolio-app-series-part-1/

solid测序列原理

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