Objective
Last v3 version , we put the entity, Service, Dao, utility in the category, so that we can easily use the same component in different cases. Although the article did not get too much praise, but believe that it must be too many people will this trick. If you have already, congratulations, this is a very important step, there is no kind of library, in the back of our many things are not easy to actually make.
Today is to talk about the use of interface, I believe many people are still interface bitter hands, most of the people are still stuck in the "Why I want to use interface", when I bring out the bad PM needs, we should be sympathetic, and feel familiar. Follow the steps in the article before you will know that the original interface can be used so easily and so useful!
Demand is clear
The more and more wicked PM presents another requirement: "Last time you put business logically and access to the category, and let our batches be used together, this idea is really great!" We now have another Web site, there is also a validate page, also want to use the AuthenticationService, but our site behind the repository are Oracle, the material structure is also different, Can you use the same authenticationservice? 』
Of course you can! After reading this article, I hope you can also talk to PM with this big voice: "Of course you can!" 』。
First of all, we have a list of functional requirements:
- Page One
- Business Logically album
- DB Source is different
Let's take a look at the "usually" people get this demand, what they might do:
Simply put, we'll pass one more of the parameters to AuthenticationService to decide which site to call, and if it's Oracle's Web site, switch to the DAO method for Oracle. If it is the original SQL Server Web site, call the original SQL DAO method. One step is resolved, handsome!
So our program will change to this:
V alidate.aspx.cs
console main ()
Then it will be found that the original use of the Authenticationservice.verifypasswordbyid to change, all have to add a reference: site, which is very annoying to us, why I want a new web site needs, but to "substantial" Modify the program that originally used this service. (You may have used this service in many places), completely against the open-shut-down principle. Maybe you're using vb.net and saying, "Simple, I'm going to use optional to mark this, so I can just meet new requirements for the new Oracle Web site."
For this kind of demand, the use of optional is a chronic poison. Will gradually rot eclipses your system to the point of no way. When the optional is over 4, you will notice that the logically of this service method is not accessible at all. This kind of design leads to too little cohesion, the same service and even a single method that contains too much of a mix of responsibilities, so adding a new requirement will cause the program not to get deeper and harder.
The mountain does not turn the road, another common practice is a poison, we add a service method, so that Oracle's website call it? This way, the code does not have to change, and can meet the new needs.
The program is as follows:
after the re-structure:
Isn't it very simple to understand?
Let's see how Oracle website is used:
The person who uses this type of library will certainly have this question, what is the difference between these two methods? This makes it confusing and easy to use. And a very serious question, after all, from the Excel file? From Access? From the TXT file? From other Web service? More and more demand, our architecture will be more and more crooked, and finally collapsed and can not praya.
So, how do we solve this problem? Yes, with interface!!.
Design steps:
Cut the code all off first (laughs)! We re-think that the requirement of the original PM is that only the part of the access to the information is different, but "the part of the business logically is exactly the same", we want to be able to have a more information access function is full of new requirements. That is, to Oracle website is still the same AuthenticationService Verifypasswordbyid method, which can not change and do not want to change. And for Oracle's access to information, it still needs to pass in the ID to get the password.
Step One:
Let's start with the original Authenticationdao Querypasswordbyid method, press the right mouse button and the refactoring = captured interface.
Tick our Querypasswordbyid method and make sure.
And then our original Authenticationdao will come out: Iauthenticationdao
And the interface of the product is quite simple:
Step Two:
Add a authenticationdaofororacle category under DataAccess's folder, actually Iauthenticationdao:
will see Visual Studio Self-help us in the way that we have to actually (obey) the interface:
Then we can ignore it! Laugh
Step Three:
Then we'll adjust our authenticationservice, very simply! We will change the property of the original public Myauthenticationdao from Authenticationdao to Iauthenticationdao. The dependency of the service to call Authenticationdao directly is dependent on the interface of Iauthenticationdao, not directly dependent on a particular category.
At this point, the fact that our program is built will be successful. All of our logically are written and finished, yes, it's simple. We're already satisfied, the service is in the same position, the DAO source is different from the design, and then we just want to do the combination of the motion.
Step Four:
Back to the program we used to AuthenticationService, we had to do one more thing: Plug the DAO we want to use (that is, concrete class) to AuthenticationService. Please imagine, when we are in step three, we will open a authenticationservice to the outside, just like a puzzle to open a particular concave hole out. The class that actually makes this interface can fill this hole, and they can assemble together and play different functions.
then, let's set the middle point and see if the program is the same as the original, using Authenticationdao to access the information:
You can imagine your own program, just like the old one.Holy Warrior, orThe King of Warcraft, our program, which is a component of one, can be arbitrarily assembled by people, as long as they can "plug" (injection).
Finally, we also modified the Oracle website program. We want to use AuthenticationService in Oracle's website, and then authenticationdaofororacle this component.
when you perform a bug, you'll see that the final point is to enter the Authenticationdaofororacle:
At the end of our programming structure, as shown in the following diagram, the service should also have a interface, so that the page can only be dependent on the service's interface, allowing the service to be switched. Finally, we 3-layer:presentation layer (page, UI), Business Logic Layer (Service Class), persistence layer (Data Access object), all have Through the interface to the layer and layer of the dependency, so that our system can be flexible pumping, as well as unlimited expansion, can also be satisfied with the release-the principle of closure.
Step three supplement to say:
In step three, we mentioned that the original public propery type was changed directly to the interface and handed out to set. This "may" leads to the question that when the outside world uses authenticationservice, and there is no assign Myauthenticationdao, it will appear nullreferenceexception. Just as the person used did not tell the AuthenticationService to use the component behind it, the method went to the back of the plane.
Although this is a potential problem, it is quite reasonable to use the situation. If you really want to limit it, you can't show this type of situation, which is forcing people to use this service, be sure to assign Myauthenticationdao, we can construct in AuthenticationService, Join the Iauthenticationdao to make use of the authenticationservice scene, when new, be sure to give Iauthenticationdao's concrete class.
Either way, but you can imagine that if I use a lot of external types for this service, then my structure doesn't have to be a bunch of things. Yes, and this is a reasonable situation. In order for the province to be used every time, we have to new a bunch of concrete class instance plug to the service we want to use, so there will be the DI framework. (di=dependency injection), through the DI framework, we can make the "combination" of this matter more relaxed, and independent of the management, will not be scattered on the ground. And the DI framework, some have support auto-wiring, that is, the framework in the need to meet the structure of the type, will automatically fill in the concrete class you set the instance. Some have support injection public property. So, what kind of writing can be used to design a different DI framework, basically two are OK.
summary
through the above requirements and actually operation, I believe you already know why we want to use interface, and the concept of use is like a group. This is also why interface is usually interpreted as a "close" concept, because in fact this is the case that this class is going to make a protruding block, so long as someone has a concave situation, it is necessary to pick up the convex class.
- The use of interface, which is actually connected with the concept of the IOC. Originally our Authentication.verify (), in which the Querypasswordbyid () is dependent on Authenticationdao. Through the interface, our authenticationservice is dependent on the Iauthenticatoindao interface. This is the concept of the IOC (control inversion).
This design, we are dependent on this interface, like a notch, the back can have a lot of many kinds of protruding class to connect, so we can be used in any of the packaging.
- Using interface allows you to separate the points and make the logically of the design stable. Our system structure becomes the following:
- In addition to the original logically can be stable, through the interface, but also for the unlimited expansion of the future to lay a stable structure:
- Increased scalability. (This is left behind in the structure to talk about ...) )
Go: [ASP] The road series v4– simple use of interface "you will also IOC"