了解Android上的干净代码

作为介绍,我想回顾鲍勃叔叔的名言
您阅读本文的原因有两个。 第一个-您是程序员,第二个-您想成为最好的程序员。
假设您在图书馆里,正在寻找一些书籍。 如果图书馆是按类别分类的,那么您将很快找到所需的书籍。 此外,凉爽的室内设计和建筑将使您在此图书馆的住宿更加舒适。

与编写书籍一样,如果您想创建一些很棒的东西,那么您需要知道如何编写以及如何组织代码。 如果您有团队成员或其他拥有您(过时)代码的人,他们只需要查看变量名或包或类,他们将立即理解。 他们不需要在代码中说“ E ** l”,然后从头开始重新编写。

什么是清洁代码?




笔译
亲爱的程序员:

当我编写此代码时,只有上帝和我知道它是如何工作的!
现在只有上帝知道这一点!

在尝试优化此例程之前,它不会导致成功(极有可能),请增加时间警告警告下一个开发人员

总花费时间:567

如您所见,仅仅完成开发还不够。 如果将来他们无法弄清楚该代码,那么它将也成为技术债。

如果团队中的每个成员都可以理解,则您的代码处于“纯”状态。 除原始作者外,任何开发人员都可以阅读和改进原始代码。 有了理解,就会出现可读性,可变性,可扩展性和可维护性。

我应该照顾这个吗?


之所以要关心代码的清洁度,是因为您向其他开发人员描述了自己的想法。 这就是为什么您应该注意代码更加优雅,简单和易读的原因。

清洁代码的迹象


  • 您的代码应优雅:您的代码应使您像制作精美的音乐盒或设计精良的汽车一样微笑
  • 您的代码应重点关注:每个函数,每个类,每个模块都实现一项任务,而该任务不会因周围的细节而分心和不受污染。
  • 代码不包含重复项
  • 成功通过所有测试
  • 减少实体,方法,类等的数量

优秀的程序员与专业的程序员之间的区别在于,专业的程序员了解代码可理解性至关重要。 专业人士使用此功能来编写每个人都能理解的代码-Robert C. Martin

写出有意识的名字


选择一个好名字可能会花费很多时间,但是以后会节省更多。 变量,函数,类的名称应回答所有重要问题。 它应该告诉您它为什么存在,为什么需要它以及如何使用它。 如果名称需要注释,则名称不会显示其用途

简单的例子

// Bad variables naming var a = 0 // user ages var w = 0 // user weight var h = 0 // user height // Bad functions naming fun age() fun weight() fun height() // Bad classes naming to get user data class UserInfo() // Best practices varibales naming var userAge = 0 var userWeight = 0 var userHeight = 0 // Best practices functions naming fun setUserAge() fun setUserWeight() fun setUserHeight() // Best practices classes naming to get user data class Users() 

类名


类和对象必须是名词,例如Custom,WikiPage,Account和AddressParser。 避免使用“经理”,“处理器”,“数据”或“信息”之类的词。 还要记住,类名不应该是动词。

方法名称


方法名称应为动词,例如postPayment,deletePage或save。 访问修饰符,谓词应按其值命名,并按JavaBean标准使用前缀get,set和set进行命名。

在继续之前,请稍事休息,购买咖啡和饼干。



好的,现在让我们继续SOLID原则。

编写遵循SOLID原则的代码


这些原则由Bob叔叔开发,SOLID是一种缩写,描述了一组旨在编写良好代码的原则。

单一责任原则(S)


这意味着每个班级应该只承担一个责任。 更改班级的理由不应超过一个。 无需仅仅因为可以做到就将所有内容添加到您的课程中。 将大班分成小班,避开上帝的班。

一个例子:

我们在onBindViewHolder内部有一个带有业务逻辑的RecyclerView.Adapter

 class MyAdapter(val friendList: List<FriendListData.Friend>) : RecyclerView.Adapter<CountryAdapter.MyViewHolder>() { inner class MyViewHolder(view: View) : RecyclerView.ViewHolder(view) { var name: TextView = view.findViewById(R.id.text1) var popText: TextView = view.findViewById(R.id.text2) } override fun onBindViewHolder(holder: MyViewHolder, position: Int) { val friend = friendList[position] val status = if(friend.maritalStatus == "Married") { "Sold out" } else { "Available" } holder.name.text = friend.name holder.popText.text = friend.email holder.status.text = status } override fun getItemCount(): Int { return friendList.size } override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyViewHolder { val view = LayoutInflater.from(parent.context).inflate(R.layout.item_friendlist, parent, false) return MyViewHolder(view) } } 

这使得RecyclerView.Adapter不完全负责,因为它在onBindViewHolder内部包含业务逻辑。 此方法仅负责将数据插入视图中。

开闭原理(O)


软件实体必须打开才能进行扩展,但必须关闭才能进行修改。 这意味着如果您正在开发A类,而您的同事将要更改该类内部的功能。 他们可以通过扩展此类而无需更改类本身来轻松地做到这一点。
一个简单的示例是RecyclerView.Adapter类。 您可以轻松地扩展它并创建具有非标准行为的自己的适配器,而无需修改RecyclerView.Adapter本身。

 class FriendListAdapter(val friendList: List<FriendListData.Friend>) : RecyclerView.Adapter<CountryAdapter.MyViewHolder>() { inner class MyViewHolder(view: View) : RecyclerView.ViewHolder(view) { var name: TextView = view.findViewById(R.id.text1) var popText: TextView = view.findViewById(R.id.text2) } override fun onBindViewHolder(holder: MyViewHolder, position: Int) { val friend = friendList[position] holder.name.text = friend.name holder.popText.text = friend.email } override fun getItemCount(): Int { return friendList.size } override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyViewHolder { val view = LayoutInflater.from(parent.context).inflate(R.layout.item_friendlist, parent, false) return MyViewHolder(view) } } 

芭芭拉·里斯克(Barbara Lisk)换人原则(L)


子类应补充父类,而不要对其进行更改。 这意味着子类必须覆盖不违反该父类功能的父方法。 例如,我们创建一个具有onClick()侦听器的类接口,然后在MyActivity中应用该侦听器,并在调用onClick()时为其提供Toast操作。

 interface ClickListener { fun onClick() } class MyActivity: AppCompatActivity(), ClickListener { //........ override fun onClick() { // Do the magic here toast("OK button clicked") } } 

接口分离原理


该原则指出,客户端不应依赖于他不使用的方法。
这意味着如果您要编写类A并向其添加另一个类B的功能,则无需在类B中重新定义所有类A。

示例:在我们的活动中,我们需要实现SearchView.OnQueryTextListener(),但是我们只需要onQuerySubmit()方法。

 mSearchView.setOnQueryTextListener(object : SearchView.OnQueryTextListener{ override fun onQueryTextSubmit(query: String?): Boolean { // Only need this method return true } override fun onQueryTextChange(query: String?): Boolean { // We don't need to implement this method return false } }) 

我们该怎么做? 容易! 只需创建一个回调和一个扩展SearchView.OnQueryTextListener()的类

 interface SearchViewQueryTextCallback { fun onQueryTextSubmit(query: String?) } class SearchViewQueryTextListener(val callback: SearchViewQueryTextCallback): SearchView.OnQueryTextListener { override fun onQueryTextSubmit(query: String?): Boolean { callback.onQueryTextSubmit(query) return true } override fun onQueryTextChange(query: String?): Boolean { return false } } 

因此,我们将其添加到视图中

 val listener = SearchViewQueryTextListener( object : SearchViewQueryTextCallback { override fun onQueryTextSubmit(query: String?) { // Do the magic here } } ) mSearchView.setOnQueryTextListener(listener) 

或者在Kotlin中使用扩展功能

 interface SearchViewQueryTextCallback { fun onQueryTextSubmit(query: String?) } fun SearchView.setupQueryTextSubmit (callback: SearchViewQueryTextCallback) { setOnQueryTextListener(object : SearchView.OnQueryTextListener{ override fun onQueryTextSubmit(query: String?): Boolean { callback.onQueryTextSubmit(query) return true } override fun onQueryTextChange(query: String?): Boolean { return false } }) } 

 val listener = object : SearchViewQueryTextCallback { override fun onQueryTextSubmit(query: String?) { // Do the magic here } } mSearchView.setupQueryTextSubmit(listener) 

依赖倒置原则


依赖抽象,不依赖特定的东西。
对Bob叔叔的依赖反转的定义包含两个概念。

上级模块不应依赖于下级模块。 两者都应与抽象联系在一起。 抽象不应依赖细节。 细节应取决于抽象。 实现复杂逻辑的高级模块应该易于重用,而无需更改低级模块。 为此,您需要输入一个抽象,将上层和下层的模块彼此分开。

这个MVP模式的简单示例。 您有一个接口对象,可以帮助您与特定的类进行通信。 含义-UI类(活动性/片段)不需要知道presenter方法的实际实现。 因此,如果您在演示者内部进行更改,则UI类不必担心这些更改。

让我们看一个例子

 interface UserActionListener { fun getUserData() } class UserPresenter : UserActionListener() { // ..... override fun getUserData() { val userLoginData = gson.fromJson(session.getUserLogin(), DataLogin::class.java) } // ..... } 

现在在活动

 class UserActivity : AppCompatActivity() { //..... val presenter = UserPresenter() override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) // Activity doesn't need to know how presenter works // for fetching data, it just know how to call the functions // So, if you add method inside presenter, it won't break the UI. // even the UI doesn't call the method. presenter.getUserData() } //.... } 

通过这种方式,我们创建了一个抽象演示者实现的接口,并且我们的视图类维护了对PresenterInterface的引用。

Source: https://habr.com/ru/post/zh-CN443662/


All Articles