0 x1, introduction

🐶 from June, off and on, is the king of the beauty of design mode to see almost, the actual combat part did not have time to see, but also benefited a lot, some changes in the way of thinking. Stomach ink is not much, do not know how to describe this feeling, say two practical application scenarios, readers will have their own ideas, by the way, bring out the summary mind map ~


Daily Development Application Example 1

When receiving new business requirements, it is no longer a matter of mindlessly splitting and outputting the schedule, copying and pasting and changing the code, but more considerations: what expansion may be possible in the future, whether repetitive business can be abstracted and reused, etc. Two examples:

1. There are different roles in the App: second-level agent, second-level responsible person, third-level agent and third-level responsible person. Then there is a list page, and different roles have different interactions

What would you do if you did it in code? Back in the day, I would have done this, put all my logical business in a Fragment, a bunch of if-else

class UserInfoFragment: Fragment() {
    / / loading fragments
    fun loading(a) {
        if(isLeader) {
            if (isSecond) {
                //
            } else {
                //}}else {
            if (isSecond) {
                // Secondary proxy
            } else {
                // Level agent}}}// Add a client
    fun addCustomer(a) {
        if(isLeader) {
            if (isSecond) {
                //
            } else {
                //}}else {
            if (isSecond) {
                // Secondary proxy
            } else {
                // Level agent}}}// The same goes for the following
    
    / / search
    // Select the agent project
    / / filter
    / / sorting
    / / TAB to switch
}
Copy the code

If else, if you want to cry, if you have another class of characters, you have to set another if-else layer, which is a huge change, and you have to change every method.

You might say that you can simplify the judgment by defining a constant attribute/enumeration to mark a class of roles, starting the judgment condition and distinguishing the roles, instead of if-else every time:

class UserInfoFragment: Fragment() {
    var role = 0    // 1 secondary agent, 2 secondary responsible person, 3 tertiary agent, 4 tertiary responsible person
    
    fun init(a) {
        if(isLeader) {
            if (isSecond) {
                role = 2
            } else {
                role = 4}}else {
            if (isSecond) {
                role = 1
            } else {
                role = 3}}}/ / loading fragments
    fun loading(a) {
        when(role) {
            1-> Secondary agent2-> Second person in charge3-> Tertiary agent4-> Level 3 Responsible person}}Copy the code

In fact, there’s no escaping the judgment that when the character changes, there’s still a lot of code to move around. How do you write it to keep it scalable?

Abstract + polymorphic + strategic pattern

Business logic can be abstracted into an object, where different actors enter the page and perform the same business logic, albeit differently, abstracting out a behavioral interface:

interface IOperate {
    fun loading(container: Int)
    fun addCustomer(a)
    fun search(select: SelectItem? = null)
    fun selectAgentProject(select: SelectItem? = null)
    fun filter(height: Int, y: Int, select: SelectItem? = null, after: (() -> Unit)? = null)
    fun order(height: Int, y: Int, after: (() -> Unit)? = null)
    fun switchTap(pos: Int)
}
Copy the code

We then define an abstract role class to implement this interface, as follows:

  • Different roles, same logic rewritten here, same includes all the same and part of the same. Partially identical means that parts of the code have the same logic, such as a burial point, which performs differently but at the same burial point. Subclass override method, call super.xxx() to reuse the same code, and then rewrite different logic.
  • Completely different logic is not implemented in the parent class, but given to the concrete child class implementation
abstract class Role(protected var mFragment: BaseFragment) : IOperate {
    abstract var type: String   // Describe the field
    
    / /...
    
    override fun addCustomer(a) {
        if (ClickFastUtils.isFastClick()) return
        mFragment.go(AddCustomerFragment::class.java)
        umAddClick.um(mFragment.context)
    }
    
    override fun filter(height: Int, y: Int, select: SelectItem? , after: (() ->Unit)? {
        umScreenClick.um(mFragment.context)
    }
    
    / /...
}
Copy the code

Then there is the concrete role class, as shown below:

class SecondAgentRole(fg: BaseFragment) : Role(fg) {
    override var type = "Secondary agent/broker"
    
    override fun loading(container: Int) {
        mFragment.childReplace(SecondAgentListFragment.newInstance(), container)
    }

    override fun filter(height: Int, y: Int, select: SelectItem? , after: (() ->Unit)? {
        super.filter(height, y, select, after)
        if (select == null) {
            shortToast("You are not in any agent project, can not view the project client!")
            return} after? .invoker()/ /... Other logic}}Copy the code

Then comes the Fragment, which is very simple because the logic is split into the corresponding character:

class CustomerFragment : BaseFragment() {
    override fun initData(bundle: Bundle?).{ diffRole()? .loading(R.id.fly_content)// Separate user roles and load corresponding fragments
    }
    
    // Differentiate user roles
    private fun diffRole(a): Role? = when {
        isLeader && isSecond -> SecondPrincipalRole(this) isLeader && ! isSecond -> ThirdPrincipalRole(this)
        !isLeader && isSecond -> SecondAgentRole(this)! isLeader && ! isSecond -> ThirdPrincipalRole(this)
        else -> null}}Copy the code

Well, there was a character change, and it was pretty minor:

  • Change judgment logic → change only in diffRole() method
  • Write a Role subclass and modify the diffRole() method
  • Delete the role → Remove the subclass of the role directly and change the diffRole() method

Wonderful ah, at that time just want to criticize words, also have side effect, is to write a few more categories, 23333.

In addition, it should be noted that the design mode can not be forced to be rigid, but also depends on the specific scene, such as here, because the business logic is relatively fixed, can be drawn in this way, but some business logic often changes or the logic difference between roles is too large, this kind of play is not very suitable, may need further abstraction.


Routine Development Application Example 2

There are a lot of list pages in the App, the layout is RefreshLayout and Recyclerview, and then the logic is like this:

  • Data initialization (assign initial values, parse various pass parameters, customize Adapter initialization)
  • UI initialization (parameter abnormal check error display error UI, RefreshLayout setting pull-up refresh and pull-down refresh logic, RecyclerView setting)
  • Request interface, update UI(normal state, abnormal state)

One solution is to use the AndroidStudio template to generate it automatically.

You can also use abstractions + generics + polymorphisms + callbacks as I did to simplify lazy, core extraction changes

  • View → list may display different layouts → Controlled by Adapter → associate different beans
  • Data → list may display different data → controlled by Request → associate different Request and Response → List of beans in Response, which changes

It’s not hard to pick out three classes that change:

  • Bean → bind Adapter data to list in Response
  • Request → Different lists Request different interfaces and parameters
  • Response → Different list request interfaces have different Response results

Can be defined as generic, as shown in the following example:

abstract class DefaultPrlRecFragment<D, Q : Serializable, S : Serializable> : BaseFragment() {
    abstract val mAdapter: BaseQuickAdapter<D, BaseViewHolder>? / / adapter
    abstract val mReq: Q    / / request
    abstract val mObservable: Observable<Response<Bean<S>>> / / interface
    protected var mData = ArrayList<D>()  / / data
}
Copy the code

When subclassing, pass in the corresponding type, and then go to the logical abstraction, first the data processing section:

// Read various incoming data or do some preparation, return true for normal load, false for exception
abstract fun prepareData(bundle: Bundle?).: Boolean

override fun initData(bundle: Bundle?). {
    if (prepareData(bundle)) {
        // Display normal
    } else {
        // Display abnormal page}}// Do some preparatory operations before initiating the request
abstract fun beforeRequest(a)

// Load the request
protected fun loadRequest(isRefresh: Boolean = false) {
    // Request processing
}

// Request response content parsing, extract data
abstract fun parseData(s: S): DataEntity?

// The parsed data class
inner class DataEntity(
    varlist: ArrayList<D>? .var allRows: Int.// Total number of records
    var pageNum: Int   / / the total number of article
)
Copy the code

Next comes the view, which pulls the interaction into an interface and then calls back in the specific business logic:

private var mListener: InteractiveListener? = null // Interface InteractiveListener {fun listEmptyCallback() // listNormalCallback() // listNormalCallback is displayed properly fun ListItemClickCallback (position: Int) / / list click fun listItemLongClickCallback (view: the view, the position: Int) // list long press Fun onRefreshCallback() // Refresh list fun onLoadMoreCallback() // load more} Don't have to rewrite all method) the abstract class SimpleInteractiveListener: InteractiveListener { override fun listEmptyCallback() {} override fun listNormalCallback() {} override fun listItemClickCallback(position: Int) {} override fun listItemLongClickCallback(view: View, position: Int) {} override fun onRefreshCallback() {} Override fun onLoadMoreCallback() {}} // Add interactive interface fun addInteractiveListener(listener: InteractiveListener) { this.mListener = listener }Copy the code

The following is an example of a call:

Fragment: Inherit the class, pass in three data types, and override abstract members and methods:

Then came the crossword puzzle, as shown below:

You can create a Fragment with pagination in just three steps


0x2 core Summary diagram

The above two examples are strongly related to the business I do and should be difficult to carry directly, but it should be possible to use for reference. Of course, the author is just a glimpse of the door, there must be a better way to achieve, is to point out the importance of learning design patterns. Then summarize a wave sections before crash will back) (interview, specific details can visit: read the book “the thin | design pattern of the beauty of” reading, thank you ~

With OOP concept

Design principles

Design patterns


0 x3, summary

Recently, I have been busy with all kinds of things. In addition to the daily development and iteration of the company, I have to memorize the eight-part essay and run around for interviews. I am tired, but I have also gained a lot


🤩🤩🤩 Nuggets official benefits

🤡 some time ago to apply for a wave of nuggets around, I thought the hope was slim, the results listed, ha ha 😆, send a wave of small gifts wow 🎁 ~

A lottery

By 24:00 on September 10th, more than 10 people have interacted in the comments section (not including me), and two lucky winners 🧒 will be selected randomly in the comments section to send a gold digging badge of BlingBling✨✨ respectively!!

Drawing time: September 12 noon 12:00, when I will contact the winning partner ha, thank the nuggets official support to this activity 🥰!