Before introducing the use of egg.js, let’s look at the MV* pattern most commonly used in Web development, so that we can better understand the directory structure of egg.js
MV* refers to various Web design patterns such as MVC, MVP and MVVM, which improve the way code is organized by separating concerns. Design patterns are not created out of nothing, but are constantly refined to solve complex problems. Even if you have not read the introduction of these design patterns, you may have used the ideas in your daily development
The simplest example
Use a simple example to illustrate the various design patterns
The page has a span with the ID container, and clicking the button increases its content by 1
<div>
<span id="container">0</span>
<button id="btn" onclick="javascript:add()">+</button>
</div>
<script>
function add (){
const container = document.getElementById('container');
const current = parseInt(container.innerText);
container.innerText = current + 1;
}
</script>
Copy the code
The logic of view rendering and data processing is mixed together, and as the business logic becomes complex, the code gets out of control and becomes difficult to maintain
MVC
MVC stands for Model View Controller
- Model: The Model layer, data related operations
- View: The View layer, the user interface rendering logic
- Controller: Communication bridge between Controller, data model and view
MVC model has many variations and data flow modes. The most traditional MVC model isolates View rendering and data processing, receives View operations through the controller and transmits them to the data model. When the data is ready, the data model drives View rendering
The above example is written in the MVC pattern for simple code separation
<div>
<span id="container">0</span>
<button id="btn">+</button>
</div>
Copy the code
Const currentValue = parseInt(node.innerText); const currentValue = parseInt(node.innerText); const newValue = currentValue + 1; // Update view node.innerText = current + 1; }Copy the code
const button = document.getElementById('btn'); // Response view directive button.addeventListener ('click', () => {const container = document.getelementById ('container'); // Call model add(container); }, false);Copy the code
- The view layer is the simplest and handles rendering of the page
- The model layer defines the implementation of the +1 operation and updates the view data
- When the user clicks a button, the controller forwards the request to the model for processing. In Web development, the controller is also responsible for the routing of general page and interface requests.
In the example above, in order to isolate data processing from the UI as much as possible, the Controller gets the Container node and passes it to the Model as a parameter. In this way, the Controller needs to understand the View, which is still coupled to the implementation of the View. In MVC practice quite a bit of the business logic will actually be written in the Controller, because the Controller is positioned as a bridge between the View’s Model and this part of coupling is acceptable
However, because the update of the View is handled by the Model, the Model inevitably needs to be coupled with the implementation of the View. The observer Mode can be used to let the View listen to the change of Mode data to make updates, but the implementation of the View depends on the Model
MVP
MVP is the abbreviation of Model View Presenter, which can be said to be an improvement of MVC mode. Compared with MVC, there are partial changes in the tasks and data flow mode of each layer
- Model: Data processing unrelated to a specific business
- View: User interface rendering logic
- Presenter: Responds to view commands and performs related business processes. If necessary, it will call Model to retrieve underlying data and return the command results to the view to drive the view rendering
The MVP model has several core changes from MVC
- The View is completely isolated from the Model, which is no longer responsible for business logic and View changes, but only for the underlying data processing
- Presenter takes over routing and business logic, but requires the View to implement the View Interface, which is convenient to decouple from the specific View and can not rely on UI for unit testing
- The View layer is only responsible for issuing instructions and rendering UI according to data, and no longer actively listens for data changes, so it is also called passive View
Modify the above example using MVP mode
<div> <span id="container">0</span> <button id="btn">+</button> </div> <script> // View Interface const globalConfig = { containerId: 'container', buttonId: 'btn', }; </script>Copy the code
function add (num) {
return num + 1;
}
Copy the code
const button = document.getElementById(globalConfig.containerId); const container = document.getElementById(globalConfig.buttonId); // The response view directive button.addeventListener ('click', () => {const currentValue = parseInt(container.innerText); Const newValue = add(currentValue); // Update the view container. InnerText = current + 1; }, false);Copy the code
This way the Model handles only business-neutral data processing and becomes very stable, while the Presenter and View are bridgable via interface/configuration, much less coupled than direct MVC
You can see that MVPS do a better job of separating data from view than MVC, and most of the time using MVC is actually using MVPS
MVVM
MVVM can be written as MV-VM, which is short for Model View-ViewModel. It is a variant of MVP mode. View and Model have the same responsibilities as MVP. ViewModel, however, relies on DataBinding to automatically associate the View with the Model. The framework simplifies the functions of Presenter by updating the View for application developers as data changes
Vue, which is familiar with the front end, uses the MVVM pattern to implement sample functions
The sample functionality can be easily implemented with Vue, but the MVVM sample code is deliberately circumnavigated
<div id="test"> <! - data binding and view - > < span > {{counter}} < / span > < button v - on: click = "counterPlus" > + < / button > < / div >Copy the code
function add (num) {
return num + 1;
}
Copy the code
new Vue({ el: '#test', data: { counter: 0 }, methods: { counterPlus: Function () {this.counter = add(this.counter); }}})Copy the code
We bind the data to the View in the View, update the data in the ViewModel, and the View changes automatically. DataBinding is implemented by the framework
conclusion
MVC, MVP, MVVM three popular design patterns are mainly to solve the separation of data and view logic, there are many variations in actual use, in general
- MVC makes the first step of the separation of View and data, which is simple to implement, but the separation of View, business logic and underlying data model is not complete
- MVP completely decoupled the View from the Model through Presenter, and at the same time stripped the business logic and the underlying data logic, making the Model stable, but Presenter can be relatively bloated in the case of complex business logic
- MVVM implements the view and DataBinding via DataBinding, but relies on the framework implementation, increasing the cost of understanding and complexity of debugging in case of misuse
There is no absolute superior or inferior design mode, and the specific choice depends on the scale of the project and the cooperation of the team. Although Controller is used in the directory structure of egg.js introduced later, it is actually MVP mode