Maximize the reusability of Java code
- overcome the defects of traditional OO methods in reuse
Summary: Don't give up the efforts of writing reusable code! This article describes three ways to modify existing code to improve their reusability.
There seems to have an increasingly common point of view in the programmer, thinking that reuse is just a myth. Perhaps it is difficult to increase the difficulty in the traditional object-oriented programming method. This article describes three steps from another different way to make reuse.
Step 1: Implement the functionality from the method of class instance
Due to lack of accuracy, class inheritance is not a very ideal code reuse mechanism. In other words, if you do not inherit a class of data members and other methods, then you cannot reuse a separate way of this class. These additional unnecessary baffles make the code reuse the code complicated. The derived class is also affected by additional complexity on its parent class: the impact on the child's changes will affect the child; when modifying any class, we are hard to remember which method is covered, which is not And whether the method covered will call the corresponding method in the parent class and unveiled very clearly.
Any method for performing a single conceptual task should be able to be a preferred and independent existence. In order to achieve this goal, we must go to the process of programming mode, remove the code from the method of class instance, and form a process with global visibility. In order to improve the reusability of this process, the process code should be written like a static general method: each process can only use its own input parameters, can only call other global processes to complete their work, can not use any non-local variable. This simplification of external dependencies has reduced the complexity of the process, and also increases the possibility of using this process elsewhere. Of course, due to its structure usually become more clear, even if the purpose of removing reuse, we can also benefit from the organization of this code.
In Java, the method cannot be separated from the class and alone. Therefore, you can organize related processes and make them a common static method in a separate class. For example, for a class as follows:
Class polygon {
...
Public int getPerimeter () {...}
Public boolean isconvex () {...}
Public Boolean ContainSpoint (POINT P) {...}
...
}
It can be rewritten into the following form:
Class polygon {
...
Public int getPerimeter () {return ppolygon.computeperimeter (this);
Public Boolean Isconvex () {Return Ppolygon.isconvex (this);
Public Boolean ContainSpoint () {Return PPOLYGON.CONTAINSPOINT (THIS, P);
...
}
Here, NPOLYGON should look like this:
Class PPOLYGON {
Static Public Int Computeerimeter (POLYGON POLYGON) {...}
Static Public Boolean Isconvex (POLYGON POLYGON) {...}
Static Public Boolean ContainSpoint (Polygon Polygon, POINT P) {...}
}
As can be seen from the name of the class, the process of the package package is mainly related to the object of the Polygon type. P in front of the name indicates that the unique purpose of this class is to organize a common static process. In Java, the name of the class is not a standard approach at lowercase letters, but it does not perform a common class function like PPLOYGON. That is, it does not represent a type of object, which is just the entity used for code organizations required by the language itself.
In this example, the overall impact of the change in the code is to make the customer code not to inherit from Polygon to reuse its functions. The function of the Polygon class is now available in the process of the PPOLYGON class. Customer code only uses the code you need, there is no need to care about itself. This does not mean that in this new process programming mode, the class does not serve more useful purposes. On the contrary, the class performs the necessary work of the organization and packaging object data. And their ability to achieve polymorphism through multiple interfaces provides significant support for code reuse, which will be discussed in the next step. However, since the functional implementation is included in the instance method, the code reuse and polymorphism support should not be an optimal technique through class inheritance.
A briefly mentioned a slightly different technologies in a broad book "Design Patterns". Strategy Pattern advocates that each member of the correlation algorithm is encapsulated under a universal interface so that the client code can be exchanged using its algorithm. Since an algorithm is typically encoded as one or several independent processes, this package more focuses on the reuse of the process of performing a separate task, rather than performing multiple tasks, and reuses the objects of the code and data. This step reflects the same basic idea.
However, an algorithm is encapsulated under an interface means encoding an algorithm as an object that implements an interface. This means that we still depend on the process coupled to the data and other methods of the object, which makes it complicated. There is also a problem with such an issue. Each time you need this algorithm, you must instantiate these objects, which will reduce the performance of the program. Fortunately, the design pattern provides a solution to these two issues. You can apply the en suite mode when encoding the policy object (Flyweight Pattern, Translator Note: There is also a translation for lightweight mode), so that each object will only have an example of a common shared (this Performance issues), and each shared object is not maintained in the access interval (which is not a data member, which is aimed at most coupling issues). The resulting product-policy mode is very similar to those mentioned in this step to encapsulate the functionality in the global visible, stateless process. (Translator Note: The above two paragraphs may be readily difficult, suggesting that the readers of interest mentioned in the article "Design Mode" book, Erich Gamma is waiting, Li Yingjun and other translations, Machinery Industry Press publishing. )
Step 2: Change the non-original input parameter type to the interface type
In object-oriented programming, the true basis of code reuse is to utilize polymorphisms through interface parameter types, rather than through class inheritance, as described in Allen Holub in "Build User Interfaces for Object-Oriented System, Part 2":
"... You should be reused by the interface instead of class programming. If all parameters of a method are references to a known interface, this interface is implemented by some of the classes you don't know, then this method can operate this. Some objects: When writing the code of the method, the class of these objects does not exist. From a technical statement, it can be reused is the method, not the object that is passed to the method. "
Applying the method of Holub to the results obtained in the first step, as long as a block function code can be independently existed as a global visible process, you can change its input parameters of each class type (class-type). For an interface type, this can further improve the potential of its reuse. Then, any class of objects that implement this interface type can be used as a parameter, not just for the original class. Thus, this process is available to a large number of object types that may exist.
For example, there is such a global visible static process
Static Public Boolean Contains (Rectangle Rect, INT X, INT Y) {...}
This method is used to check if a given rectangle contains a given point. In this example, the type of Rect parameter can be changed from the Rectangle class to the interface type, as shown below: Static Public Boolean Contains (Rectangular Rect, Int x, int y) {...}
Rectangular can be the interface below:
Public interface reccTangular {
Rectangle getBounds ();
}
Now, all classes that can be described as rectangular (also means that the Rectangular interface) can be used as a Rect parameter transmitted to prectangular.contains (). We have better reusability by relaxing the type of parameter type transmitted.
However, in this example, the getBounds method of the Rectangular interface returns a Rectangle type. You may doubt whether to use this interface has a real value; in other words, if we know that the access process will return one when it is called Rectangle, why not directly enter the rectangle replacement interface type? The most important reason not to do is related to the collection, suppose there is such a method:
Static Public Boolean Areanyoverlapping (Collection Rects) {...}
The purpose of this method is to check if any rectangular object in a given collection is overlapping. Then, when the method is traversed within the collection, if the object shape (CAST) is not possible, how can I access the rectangular area of the object? The only choice is to make the object shape into its specific type (we have until it has a method that can return Rectangle), which means that the method must know what type it has to operate in advance. This is precisely this step figure first to avoid problems!
Step 3: Select the type of input parameter interface of low coupling
After completing the second step, what kind of interface type should you choose to replace a given type? The answer is to fully describe the needs of the process through parameters, and at the same time have the minimum amount of interface types. The more simple interfaces to which the parameter object is to be implemented, the larger the chance to implement this interface, thereby, the more the objects can be used as the parameters. It can be easily seen by the following example:
Static Public Boolean Areoverlapping (Window Window1, Window WINDOW2) {...}
This method is used to check if two windows (assuming are rectangular windows) overlap, if this method only requires the rectangular coordinates of the two windows from the parameter, the type of simplified parameters makes it reflecting this fact is a better choice. :
Static Public Boolean AreoverLapping (Rectangular Rect1, Rectangular Rect2) {...}
The above code assumes that the previous WINDOW type object can also implement the Rectangular interface. Now you can reuse the functions included in the first method for all rectangular objects.
You may experience many times when an interface can fully determine which content you need to get through parameters, there is too much unnecessary method. In this case, a new public interface should be defined in the global namespace for other methods that may face the same dilemma.
You may also find a separate interface when it is determined what you need to obtain by a parameter you need to pass through a single process. You should only use this interface for this parameter. This usually occurs when you want to use the parameters like a function pointer in the C language. For example, the following process:
Static Public Void Sort (List List, SortComparison Comp) {...} This procedure uses the comparison object CoMP provided by the parameter, sort it by comparing all objects in the given list, Sort is called all requirements for COMP. A separate method is compared. Therefore, SortComparison should be only an interface with one way:
Public interface sortcomparison {
Boolean comesbefore (Object A, Object B);
}
The sole purpose of this interface is to provide a hook (HOOK) that is linked to its completion task, so SortComparison cannot be reused elsewhere.
Conclude
The three steps described above are used in conventional, according to the code written in the relative conventional object-oriented method. These steps are combined with object-oriented programming techniques to form a new method that can be used in future code preparation, which can increase the reusability and cohesiveness of the code while reducing coupling and complexity.
Obviously, these steps cannot be applied to those who are not suitable for reuse in nature. Such code usually appears in the presentation layer. For example, the program is used to create a user interface, and the control code associated with the process of completing the input event with the process of completing the actual work, is a very different code that is different in different programs. This code is reused. Almost impossible.