Open interfaces and hide details-the principle of opening and closing based on the basic object-oriented principles

Source: Internet
Author: User
Open interfaces and hide details-the principle of opening and closing based on the basic object-oriented principles   We know that the code we have written has undergone multiple tests. For example, you need to pass unit testing and integration testing by developers, then go to White-box testing and black-box testing by testers, and finally perform certain tests by users. After a long test, the code can be put into use. However, maintenance and upgrade of software products is an eternal topic. During the maintenance process, you may need to constantly add some small functions. During the upgrade process, you need to add some large functions. That is to say, software products require extended functions at any time. The extension of this function requires us to change the original code. For example, we can modify the original code to extend its functions. However, modifications to the original code will profoundly affect all aspects of the original function: it may introduce new errors to the old Code, so that you have to make large-scale modifications to the old code; even if the new Code does not affect the old code, you also have to perform a comprehensive test on the original system. All the problems listed above are the cost of system function expansion. In other words, the system we designed must be a well-scalable system. How can we design a system with good scalability? The open and closed principle tells us that the software system must be closed to changes, but open to extensions. In other words, our system is a scalable system, not a modifiable system. The dependency inversion principle is a solution proposed to meet the open and closed principles: programming interfaces. Only dependency abstraction can be used to expand the system, that is, to implement the defined interface when the system is extended, rather than generating new classes. For example, we need to use a class, our code will be written like this: Dog dog = new dog ();...... At first glance, this code is poor in scalability, because if we need to add a new class: Cat, we must modify the above Code as follows: // first determine the object to be generated if (animal. equals ("dog ")){

Dog dog = new dog ();

......} Else if (animal. Equals ("cat ")){

Cat cat = new CAT ();

......} This is not enough. If our new animal classes are constantly increasing, we need to constantly modify the above Code, which is obviously quite bad code. The code we want is as follows:

Animal animal = factory. getinstance (animalname );

This idea is very simple. Our client depends on an animal interface, and we don't want to worry about the specific instance. We only give you a code representing the instance, and you should generate the instance. This is the factory model. Note that the simple factory mode simply transfers the client-to-class instance dependencies to the factory class. This only implements part of the open and closed principle. For client calls, the open and closed principle is met, but not for the factory class. The weakness of the simple factory model allows us to further optimize the model so that we can use the abstract factory and factory methods. We can also further optimize the factory Mode Based on Java reflection, so that the mode meets the open and closed principles to a greater extent. Command mode, rule mode, and state mode all share the same principle. They all share the separation of concerns: Command mode is the separation of behaviors, and Policy mode is the separation of algorithms, status mode is the separation of States. The separation of these concerns first satisfies the single responsibility principle. But can we just separate these concerns, such as behaviors, algorithms, and states? Let's take the command mode as an example to look at this problem. Our initial client code is: If (condition1 ){

// Do action 1

......} Else if (condition2 ){

// Do action 2

......}...... Then we separate all the actions: public class Action1 {

Public void doaction1 ()

{......}} Public class Action2 {

Public void doaction2 ()

{......}} Then the client changes to: If (condition1) {Action1 action = new Action1 (); action. doaction1 ();} else if (condition2) {Action2 action = new Action2 (); action. doaction2 ();} does not obviously improve the scalability of the client code. If we add a new behavior, we must first add the class of this behavior, then, the client still needs to be modified, which does not meet our open and closed principles. To meet the open/closed principle, the first step is to further abstract the behavior class and give these behavior classes a common interface: public interface action {

Public void doaction ();

} Then all our behavior classes implement the Action interface. In this way, the client code is changed to: action;

If (condition1) Action = new Action1 ();

Else if (condition2) Action = new Action2 ();

...... Action. doaction (); this is the solution of the command mode. With the interface, it lays the foundation for system expansion. For example, if the client code above transfers the instantiation of a specific class to a factory, the client code will look like the following:

Action action = factory. getinstance (condition );

Action. doaction (); in this way, the client's scalability satisfies the open and closed principles. The combination mode implements the same interface for both the whole and part of the system for the sake of system scalability, so that both the whole and part of the interface can be expanded, and the open and closed principles are well met. For example, the relationship between the Optical Disc Box and the optical disc is "whole and part". The optical disc box can be regarded as a whole, while the optical disc is a part, both of which implement the same interface. In this way, we can expand the "whole". For example, the optical disc box can be placed in the toolbox. Here, the toolbox is a larger "whole" and we can implement the above interface, does not have too much impact on the system. We can also expand the "part", such as some soft box boxes in the toolbox, or a floppy disk in the soft box. The assembler mode implements the same interface by both the assembler and the assembler. The proxy mode implements the same interface between the proxy class and the actual work class. The purpose of the proxy mode is to satisfy the principle of opening and closing. Because it implements a unified interface, for the assembler and the actual work class, they can expand more classes to implement this interface, so as to meet the scalability requirements of the system. We will not talk about how these models implement the principle of opening and closing in detail here. You can use the relevant models to understand them.

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.