background

One day, the product owner came to me and said the business had changed and he needed to add another order. I thought to myself: “small matter, is not to increase a kind of order, sprinkle water.” Because the demand is simple, I just pulled out of the collection code to put back. The product guru nodded with satisfaction and walked away with his heirloom kitchen knife.

So I happily open the editor, a look at the code, boy, I directly boy

  computed: {
    priceTitleText() {
      if ([20001.20002].includes(this.detail.orderStatus)) {
        return 'Amount due'
      } else {
        return 'Paid amount'}},Copy the code

If you want to add an order type, it is not necessary to judge the order type in every state, as shown below

    if (this.detail.orderType === 10001) {
       if ([20001.20002].includes(this.detail.orderStatus)) {
           return 'Amount due'
        } else {
           return 'Paid amount'}}else if (this.detail.orderType === 10002) { // New requirement order type
       // Because the order status is different, the display content is different
      if ([20001.20002.20003].includes(this.detail.orderStatus)) {
        return 'Amount due'
      } else {
        return 'Paid amount'}}Copy the code

This computed is fine, but there are a dozen or two listener functions in the project, so I have to add order type judgment to each one. I thought for a while, and took out my collection code, sloppy……

Using state machines

Take the above requirement for example, the current new requirement adds an order type, assuming that it will be added later, do you need to add another if else layer to the above operation? Each order type has a different business logic, and it is possible that state 1 is one representation on order type 1, but another representation on order type 2, so you have to think about how to sort the order so that the order logic is visible at a glance. That’s where the state machine comes in.

The four concepts of state machines

  • State. A state machine must contain at least two states. For example, the order type above has two states: Order type 1 and Order type 2.

  • An Event. An event is a trigger condition or password to perform an action.

  • Action. The action is performed after the event occurs. For priceTitleText above, this is an action.

  • Transition. That’s going from one state to another.

Creating a State Machine

class StatusMaker {
  constructor(detail) {
    if(! detail)return
    this.state = this.setState(detail.orderType)
    this.detail = detail
  }
}
Copy the code

Pass in the order detail data

Add state

class StatusMaker {
  constructor(detail) {
    if(! detail)return
    this.state = this.setState(detail.orderType)
    this.detail = detail
  }
  // ++ start
  setState(status) {
    if (status === 2) {
      return 'orderType1'
    } else if (status === 3) {
      return 'orderType2'}}// ++ end
}
Copy the code

State is a key property that controls how the state machine runs, so you first have to control the type of order that comes in

Add actions

Knowing the current order type, you can perform the different methods required depending on the current type.

class StatusMaker {
  constructor(detail) {
    if(! detail)return
    this.state = this.setState(detail.orderType)
    this.detail = detail
  }
  setState(status: OrderStatus) {
    if (status === 2) {
      return 'orderType1'
    } else if (status === 3) {
      return 'orderType2'}}// ++ start
  orderType1 = {
    // that: this, 
    // There is a bug in vue when accessing the instance environment through this
    // VUE internal dependency collection will continue to cycle addDep, resulting in stack burst,
    // It doesn't work on the browser, so the following method can't get the current instance inside.
    // We will change the reference of this via call.
    priceTitleText() {
       // console.log(this.thate. detail) could have accessed the instance this way
      if ([20001.20002].includes(this.detail.orderStatus)) {
        return 'Amount due'
      } else {
        return 'Paid amount'
      }
    },
  }
  orderType2 = {
    // that: this,
    priceTitleText() {
      if ([20001.20002.20003].includes(this.detail.orderStatus)) {
        return 'Amount due'
      } else {
        return 'Paid amount'}}},// ++ end
}

Copy the code

Add execution events

Simply put, it’s to perform the action we need to perform

class StatusMaker {
  constructor(detail) {
    if(! detail)return
    this.state = this.setState(detail.orderType)
    this.detail = detail
  }
  setState(status: OrderStatus) {
    if (status === 2) {
      return 'orderType1'
    } else if (status === 3) {
      return 'orderType2'
    }
  }
  orderType1 = {
    // That: this, // There is a bug in vue that causes a stack explosion when accessing the instance environment through this, which does not happen on the browser, so the following methods cannot get the current instance. Below this we will change the reference of this via call later.
    priceTitleText() {
      if ([20001.20002].includes(this.detail.orderStatus)) {
        return 'Amount due'
      } else {
        return 'Paid amount'
      }
    },
  }
  orderType2 = {
    // that: this,
    priceTitleText() {
      if ([20001.20002.20003].includes(this.detail.orderStatus)) {
        return 'Amount due'
      } else {
        return 'Paid amount'}}}// ++ startevent (method, ... args) {const state = this.state
    if (!this[state] || !this[state][method]) {
      return false
    }
    return this[state][method].call(this. args)// Call the action to get the current instance this and pass in the args argument
  }
  // ++ end
}
export default StatusMaker
Copy the code

Thus, a state machine is complete.

Used in the vue


import StatusMaker from './statusFactory'
export default {
  data() {
     return {
         statusMaker: null}},computed: {
     priceTitleText() {
       return this.statusMaker.event('priceTitleText'.this.showFormType)
     },
     // ...
  },
  created() {
      this.statusMaker = new StatusMaker(this.detail)
  }
}
Copy the code

This way, the state machine can display different page logic depending on the type of order we pass in, very gingko.

conclusion

A state machine is essentially a state model, which makes the whole logic clearer and separates the data of different order types. But in my opinion, in use, the two order types need to write the same function repeatedly, and most of the contents are the same. I don’t know if there’s another way to optimize. Thank you very much for your comments.