The clean code learning note separates the construction and use of the system

Source: Internet
Author: User

To keep software systems clean at the system level, appropriate abstract levels and modules must be developed for the system. An effective method is to separate the construction and use of the system, because the construction and use are very different processes.

The software system should split the START process and the runtime logic after the START process. If the application objects are constructed during the START process, there will be tangle dependencies between them. Separating the focus is the oldest and most important design technique in software skills. Unfortunately, most applications fail to implement separation, and the startup process code is very special. It is mixed into the runtime logic. The following code snippet is the famous delayed initialization/assignment, the advantage of this kind of processing is that you don't have to worry about this kind of overhead structure before actually using the object, and the start time will be shortened, and the null value will never be returned.

Public service getservice () {<br/> If (null = Service) {<br/> service = new myserviceimpl (...); <br/>}< br/> return service; <br/>}

But there is a problem. When we get the service, hard encoding must depend on what myserviceimpl and its constructor need. You cannot compile without breaking down these dependencies, even if you never use this type of object at runtime.

If myserviceimpl is a heavy object, you must assign an appropriate test double or mock object to the service before conducting a unit test ).

To solve the preceding dependency problem, we have three methods:

1) Break Down Main

One of the ways to separate constructor and usage is to move the entire constructor to the main or called Main module. When designing the rest of the system, assume that all objects have been correctly constructed and set ., The main function is responsible for calling the builder to create the objects required by the system and passing them to the application. The application is only responsible for use. From the direction of the arrow, the application knows nothing about the main or constructor. It simply expects everything to be ready.

The code for simple implementation is as follows:

/** <Br/> * a configuration object for applicaton, created by builder <br/> * @ author asce1885 <br/> */<br/> public class configuredobject {</P> <p> private string majorversion; <br/> private string minorversion; </P> <p> Public String getmajorversion () {<br/> return majorversion; <br/>}</P> <p> Public void setmajorversion (string majorversion) {<br/> This. majorversion = majorversion; <br/>}</P> <p> Public String getminorversion () {<br/> return minorversion; <br/>}</P> <p> Public void setminorversion (string minorversion) {<br/> This. minorversion = minorversion; <br/>}</P> <p> Public configuredobject (string majorversion, string minorversion) {<br/> This. majorversion = majorversion; <br/> This. minorversion = minorversion; <br/>}</P> <p> Public configuredobject () {</P> <p >}</P> <p>}/** <Br/> * Create configuredobject <br/> * @ author asce1885 <br/> */<br/> public class builder {</ p> <p> private configuredobject = NULL; </P> <p> // delayed initialization <br/> Public configuredobject createconfiguredobject (string majorversion, string minorversion) {<br/> If (null = configuredobject) {<br/> configuredobject = new configuredobject (majorversion, minorversion); <br/>}< br/> return configuredobject; <br/>}</P> <p>}/** <Br/> * specific application module, configuredobject object instance is required to run <br/> * @ author asce1885 <br/> */<br/> public class application {</P> <p> private configuredobject; </P> <p> Public void run (configuredobject Co) {<br/> configuredobject = Co; <br/> system. out. println ("majorversion is:" + Co. getmajorversion (); <br/> system. out. println ("minorversion is:" + Co. getminorversion (); <br/>}</P> <p>}/** <Br/> * Main module <br/> * @ author asce1885 <br/> */<br/> public class main {</P> <p> Public static void main (string [] ARGs) {<br/> // create a builder object <br/> Builder = new Builder (); <br/> configuredobject CO = builder. createconfiguredobject ("R3", "C02"); </P> <p> // create an Application Object <br/> application APP = new application (); <br/> app. run (CO); <br/>}< br/>}

2) Introduce abstract factory methods

In the above method, the application does not know when the object co is created, but in some cases, the application is also responsible for determining the time to create the object, for example, in an order processing system, the application must create a lineitem object and add it to the order object. In this case, the abstract factory mode can be applied to allow the application to control when to create lineitem, And the constructed details are isolated from the application code ., From the direction of the arrow, we can see that the application orderprocessing and how to construct lineitem are separated. It only has the interface for abstracting factory methods. The details are implemented by lineitemfactoryimplementation on the main side. However, the application can fully control when the lineitem object is created, and even pass application-specific constructor parameters.

The simple implementation code is as follows:

/** <Br/> * lineitem entity <br/> * @ author asce1885 <br/> */<br/> public class lineitem {</P> <p> private string name; </P> <p> Public String getname () {<br/> return name; <br/>}</P> <p> Public void setname (string name) {<br/> This. name = Name; <br/>}</P> <p> Public lineitem (string name) {<br/> This. name = Name; <br/>}</P> <p>}/** <Br/> * abstract factory class <br/> * @ author asce1885 <br/> */<br/> Public interface lineitemfactory {</ p> <p> Public lineitem makelineitem (string name ); </P> <p>}/** <Br/> * specific factory class <br/> * @ author asce1885 <br/> */<br/> public class lineitemfactoryimpl implements lineitemfactory {</P> <p> private lineitem; </P> <p> @ override <br/> Public lineitem makelineitem (string name) {<br/> If (null = lineitem) {<br/> lineitem = new lineitem (name); <br/>}< br/> return lineitem; <br/>}</P> <p>}/** <Br/> * order processing class, automatically control when to create lineitem <br/> * @ author asce1885 <br/> */<br/> public class orderprocessing {</P> <p> private lineitem; <br/> private lineitemfactory; </P> <p> Public orderprocessing (lineitemfactory LIF) {<br/> lineitemfactory = LIF; <br/>}</P> <p> Public void run () {<br/> lineitem = lineitemfactory. makelineitem ("asce1885"); <br/> system. out. println ("the name of lineitem is:" + lineitem. getname (); <br/>}</P> <p>}/** <Br/> * Main module <br/> * @ author asce1885 <br/> */<br/> public class main {</P> <p> Public static void main (string [] ARGs) {<br/> lineitemfactory LIF = new lineitemfactoryimpl (); <br/> orderprocessing op = new orderprocessing (LIF); <br/> op. run (); <br/>}</P> <p>}
3) Dependency injection di

Dependency injection is an application of IOC in dependency management. Control inversion separates the second right and responsibility from the object and transfers it to another object that focuses on this, thus, SRP follows the principle of single rights and responsibilities. Because the initial setting is a global problem, this authorization mechanism is usually either a main routine or a container with a specific purpose.
JNDI lookup is a "partial" Implementation of Di. The following code snippet is in JNDI. The object request Directory Server provides a "service" that matches a specific name ":

Myservice = (myservice) (jndicontext. Lookup ("nameofmyservice "));

In the above Code, the call object jndicontext does not control the category of the actually returned object, but it still actively breaks down the dependency (nameofmyservice ).

In real dependency injection, classes do not directly break down their dependencies, but are completely passive. The class only provides the method or constructor parameter that can be used to inject dependencies (or both). Then, during the construction process, the di container will materialized the required objects, use the constructor parameters or the assignment method provided by the class to connect the dependencies. The dependency object is actually used through the configuration file or programming in a specially intended constructor. For details, see the Java di container in the Spring framework. Users define correlated objects in the XML configuration file and request specific objects in Java code.

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.