The disadvantage of MVC is that it does not distinguish between business logic and business presentation, which is not friendly to unit testing. MVP has optimized the above disadvantages. It also isolates business logic and business presentation, and the corresponding one becomes MVCP. The functions of M and V remain unchanged, the original C is now only responsible for layout, and all logic has been transferred to the P layer. The corresponding relationship is shown in the figure: The business scenario has not changed. It still displays three types of data, but the three MVCs are replaced by three MVPs (I only drew the Blog module in the figure). UserVC is responsible for configuring the three MVPs (creating their own VPs, establishing C through VPs, and C is responsible for establishing the binding relationship between VPs), and notifying their own P layers (previously notifying the C layer) to obtain data at the appropriate time. After obtaining the data, each P layer will perform corresponding processing. After the processing is completed, it will notify the bound View that the data has been updated. After receiving the update notification, V obtains the formatted data from P for page rendering, and UserVC*** lays out the rendered Views. In addition, the V layer and the C layer no longer process any business logic, and all event triggers call the corresponding commands of the P layer. The specific code is as follows:
BlogPresenter and BlogCellPresenter are the P layers of BlogViewController and BlogCell respectively, which are actually a collection of business logic. BlogPresenter is responsible for obtaining the original data of Blogs and constructing BlogCellPresenter based on these original data, while BlogCellPresenter provides various formatted data for Cell rendering. In addition, the business of likes and sharing is now also transferred here. The business logic has been moved to the P layer, and the V layer only needs to do two things: 1. Listen to the data update notification of the P layer and refresh the page display. 2. When the click event is triggered, the corresponding method of the P layer is called and the method execution result is displayed.
What the C layer does is to bind the layout to the PV (it may not be obvious here, because the layout code in BlogVC is TableViewDataSource, and the PV binding is not obvious because I was lazy and used Block for notification callback. If it is a Protocol callback, it will be very obvious). The code is as follows:
BlogViewController is no longer responsible for the actual data acquisition logic. Data acquisition directly calls the corresponding interface of Presenter. In addition, because the business logic has also been transferred to Presenter, the layout of TableView also uses Presenter.allDatas. As for the display of Cell, we replaced a large number of the original Set methods and let Cell display itself according to the bound CellPresenter. After all, the logic has been moved to the P layer. The V layer must rely on the corresponding P layer commands for corresponding interactions. Fortunately, V and M are still isolated, but coupled with P. The P layer can be replaced at will, but M obviously cannot. This is a compromise. *** is Scene, which has not changed much, except that the configuration of MVC is replaced by MVP. In addition, data acquisition also goes through the P layer instead of the C layer (however, this is not the case in the code):
There is actually a problem in the above example, that is, we assume that all events are initiated by the V layer and are one-time. This is actually not true. Let's take a simple example: on a page like WeChat voice chat, click on the voice Cell to start playing, the Cell displays the playing animation, the animation stops when the playing is completed, and then the next voice is played. In this playback scenario, if CellPresenter still only provides a playWithCompletionHandler interface as above, it will not work. Because the callback after the playback is completed must be in the C layer. After the playback is completed, the C layer will find that the CellPresenter that executes the playback command at this time cannot notify the Cell to stop the animation, that is, the event triggering is not a one-time event. In addition, after the playback is completed, when the C layer traverses to the next CellPresenterX to be played and calls the playback interface, CellPresenterX does not know who the corresponding Cell is, and of course it cannot notify the Cell to start the animation, that is, the initiator of the event is not necessarily the V layer. For these non-one-time or other layer initiated events, the processing method is actually very simple, just add a Block attribute to CellPresenter. Because it is an attribute, Block can be called back multiple times. In addition, Block can also capture Cell, so there is no need to worry about not finding the corresponding Cell. It's like this:
When playing, VC only needs to keep CellPresenter, and then pass in the corresponding playState to call didUpdatePlayStateHandler to update the state of Cell. Of course, if the VP binding is done by Protocol, then doing these things is very common and will not be described here. This is what MVP looks like. Compared with MVC, it actually only does one thing, which is to separate business display and business logic. After display and logic are separated, as long as we can ensure that V can refresh the page normally after receiving data update notification from P, then the entire business will be fine. Because the notifications received by V actually come from the data acquisition/update operations of the P layer, so we only need to ensure that these operations of the P layer are normal. That is, we only need to test the logic of the P layer and don't need to care about the situation of the V layer.
MVP is actually a very good architecture that solves almost all known problems, so why is there MVVM? Still using an example, suppose there is a Cell now. Clicking the Follow button on the Cell can be followed or unfollowed. When unfollowing, SceneA requires a pop-up window to ask first, while SceneB does not make a pop-up window. In this case, the unfollow operation is strongly related to the business scenario, so this interface cannot be called directly by the V layer, but will rise to the Scene layer. Specifically in the code, it looks like this:
The Block method seems a bit cumbersome, so let's switch to the Protocol method:
Excluding the codes like Route and Alert in VC, we can find that both Block and Protocol methods need to isolate page display and business logic, so the code goes around a little bit, which invisibly increases the amount of code. This is just one event, what if there are multiple events? It would be really difficult to write... If you look at the above code carefully, you will find that if we continue to add events, most of the code is doing one thing: the P layer notifies the V layer of data updates. The Block method will add many properties to the P layer and many setting Block logic to the V layer. Although the Protocol method only adds one property to the P layer, the methods in the Protocol will continue to increase, and the corresponding V layer will also need to add methods to implement. Now that the problem has been found, let's try to solve it. In OC, low-coupling communication between two objects can be achieved. In addition to Block and Protocol, KVO is generally considered. Let's see how KVO performs in the above example:
The code is about half as long as it should be. In addition, the logic is much clearer to read. The Cell observes the isFollowing state of the bound ViewModel and updates its display when the state changes. A simple comparison of the three data notification methods shows that everyone knows which method is more programmer-friendly, so I won't go into details. Now, when MVVM is mentioned, RAC will probably come to mind, but there is actually no connection between the two. For MVVM, RAC only provides an elegant and safe way of data binding. If you don't want to learn RAC, you can also make something like KVOHelper yourself. In addition, the charm of RAC actually lies in functional responsive programming. We should not limit it to the application of MVVM, but also use it more in daily development. That's all I want to say about MVVM, because MVVM is actually just a binding evolution of MVP. Except for the data binding method, everything else is exactly the same as MVP, except that the presentation method may be Command/Signal instead of CompletionHandler, so I won't go into details. *** Let's make a brief summary: 1. MVC is an old-fashioned architecture. Its advantage is that it divides business scenarios into multiple modules according to the display data type. The C layer in each module is responsible for business logic and business display, while M and V should be isolated from each other for reuse. In addition, each module can also be used as a reuse unit if it is properly handled. Splitting is about decoupling and reducing the burden. Isolation is about reuse and improving development efficiency. The disadvantage is that it does not distinguish between business logic and business display, which is not friendly to unit testing. 2. MVP, as an advanced version of MVC, proposes to distinguish business logic from business display, transfer all business logic to the P layer, and the V layer receives data update notifications from the P layer for page display. The advantage is that good stratification brings friendly unit testing, but the disadvantage is that stratification makes the code logic complicated and also brings a lot of code work, which is not friendly to programmers. 3. MVVM, as a master, updates data through data binding, reduces a lot of code work, and optimizes code logic. However, the learning cost is a bit high and it is not friendly to novices. 4. MVP and MVVM will create more than twice the file classes of MVC because of their layering, which requires good code management. 5. In MVP and MVVM, the relationship between V and P or VM is theoretically many-to-many. Different layouts under the same logic only need to replace the V layer, and the same layout with different logic only needs to replace the P or VM layer. However, in actual development, P or VM often degenerates into a one-to-one relationship because of the coupling of the display logic of the V layer (for example, SceneA needs to display "xxx+Name", and VM formats Name as "xxx + Name". One day, SceneB also uses this module, and all click events and page displays are the same, except that Name is displayed as "yyy + Name". At this time, VM is awkward because it is coupled with the display logic of SceneA). For such situations, there are usually two ways, one is to add states to the VM layer to determine the output state, and the other is to add another layer of FormatHelper outside the VM layer. The former may make the code ugly because of too many states, and the latter is more elegant and highly extensible, but too many layers are a bit clumsy when restoring data. You should choose according to your needs. Here is a random comment. Some articles say that MVVM is to solve the problem of bloated C-layer and difficult testing of MVC. In fact, it is not true. According to the order of architecture evolution, the bloated C-layer is mostly due to the failure to split the MVC module properly. It is enough to split it properly, and there is no need for MVVM. The difficulty of testing MVC can also be solved by MVP, but MVP is not the best. The data interaction between VPs is too cumbersome, so MVVM was introduced. When the complete MVVM appeared, we looked at the origin from the result and found that it did a lot of things. In fact, it is not, and its predecessors have made a lot of efforts!
Whether it is MVC, MVP, MVVM or MVXXX, the ultimate goal is to serve people. We focus on architecture and layering for development efficiency, and ultimately for fun. Therefore, in actual development, we should not stick to a certain architecture. Based on the actual project, ordinary MVC can cope with most development needs. As for MVP and MVVM, you can try them, but don't force them. In short, I hope everyone can do this: when designing, have a clear idea in mind. When coding, just have fun. |
<<: A widget dancing on a needle with shackles on its legs
I started writing for the official account in Aug...
Earlier, LG Electronics released a photo of its ne...
Sugarcane attraction conquers the world Apart fro...
As we all know, WeChat is the most used social AP...
The Richter's disc-bellied spider has a very ...
There is a question that has been bothering App d...
The main factors affecting the price of mini prog...
[[141235]] Many people call 2010 the first year o...
In 2020, " live streaming with goods " ...
Nowadays, many people believe that WeChat groups ...
Recently, topics such as "whooping cough rea...
Why not just change the name of the can to the di...
01Create WeChat group There are more and more fri...
"Growth hacking" must be familiar to th...
In addition to the common wintersweets, plum blos...