The Four-and-a-Half Levels of Granularization

The Four-and-a-Half Levels of Granularization

When writing object-oriented programs in the Java language, you need to know when to hide or expose details of a class, package, or component. You use Java interfaces, scope identifiers, inheritance, or package names to hide or expose a subset of functionality that another class can utilize (you do this to simplify development).

Imagine for a minute that it's the Middle Ages. The king ”who is a good one ”has to deal with some good people and some bad ones. The good people want to trade with him. The bad people want to take over his kingdom. The king could be one of two types, and each type is similar to how software is developed. All will be revealed shortly.

In response to the bad people, a paranoid king shields himself from society, effectively making it impossible for the bad people to remove him. The side effect, however, is that the king removes himself from contact with his people. As a result, the king always relies on other people for accurate information. The people who provide the information can usurp power from the king since they control the flow of information. This results in a delicate situation where the king could find himself the victim of false circumstances.

On the other hand, another type of king would be in constant contact with the people. The people would love the king, but because of the constant contact, the king would be vulnerable to assassination. Therefore, the king needs to somehow protect himself, while still being in contact with the people. The solution is that the king needs to construct a castle, a sort of house that encloses a community. In times of distress, the castle changes into a fortress to repel any potential invader. But the castle also serves a more important purpose: it provides an access point where guards can watch over everyone who enters the castle. Suspicious people are questioned.

You may have guessed by now that developing software is like being a king who builds various castles . While you may not have to worry about bad guys like the first type of king does, you will encounter some programmers who will do things they should not ”either on purpose or by mistake.

Software written too abstractly is like the king who does not want to be a target of assassination. This kind of software typically promises to be future-proof and can supposedly deal with any future changes in software technology. However, the future-proofing is only as good as the programmers who write the software. If the programmers are badly advised or miss certain details, then the future-proofing will become useless. Software that is written too loosely and that trusts the other programmers will become problematic because everybody will abuse the software and use it how they see fit. This is like the king who is worried about assassination because he trusts his people too much.

Hiding or exposing software details is called writing components . Components are like individual castles in that what is exposed from the component is like the guard at the castle who controls the flow of people. The different ways of exposing a component is called granularization . There are four-and-a-half levels of granularization. The first four are class level, package level, interface level, and Web Service level. The half level is generic-level granularization.

Class-Level Granularization

In Java, class-level granularization is limited to scope identifiers, like public , private , etc. Listing 2.1 shows the Java class definition.

Listing 2.1
start example
 public class ClassScope { void methodPackage() { System.out.println( "Scope package"); }   public void methodPublic() { System.out.println( "Scope public"); }   protected void methodProtected() { System.out.println( "Scope protected"); }   private void methodPrivate() { System.out.println( "Scope private"); } 
end example

In Listing 2.1, the class ClassScope has been declared with four individual methods . Each method has a different scope. For this level of granularization, what is important is the difference between the public method modifier and the other modifiers. When a class, method, or field is declared public, then that class, field, or modifier is available for usage by all other classes. This means that a public modifier gives the highest amount of access to the individual class and its contents. Likewise, this means you need to consider the public modifier very carefully before using it.

When you declare a class or interface public, it is important to consider the ramifications of this action. The problem is that once another class uses a public class or interface, that public class or interface is locked into a specific implementation signature. As in the castle example, we are providing a place for people to enter the castle and then one day changing the location. People will figure out where the new entrance is, but before everybody adjusts , there will be confusion, even if people are forewarned. Therefore, when you make classes or interfaces public, consider the publication final.

Package-Level Granularization

In the class example shown in Listing 2.1, some methods were declared with scope identifiers other than public . Other than the private scope modifier, the other methods are accessible from only other packages. Listing 2.2 shows a class that is visible only to the local package.

Listing 2.2
start example
 class PackageScope { void method( ClassScope cls) { cls.methodPackage(); cls.methodProtected(); } } 
end example

The class PackageScope declared in Listing 2.2 has no scope modifiers, meaning that the default scope is used, which is package scope. Package scope means that only classes within the same package can interact with the class in Listing 2.2. The method method has no scope modifiers either and is therefore package scope as well. Listing 2.2 shows how the method method can call the package methods of the class ClassScope that have a package scope.

Packages in Java are a nice feature because they allow you to group together a number of classes and interfaces as one unit. Typically, packages are created to reflect the functionality contained within the package.

Interface-Level Granularization

Interfaces are a higher level of granularization than packages because of the binding types and scope of the bindings. When referencing a class or a package, you make a direct reference to the identifier of the class or package. An interface is a bit different in that the interface that is referenced uses an unknown implementation. So, while the interface is referenced directly, the actual implementation is referenced indirectly. This makes the interface a more sophisticated kind of reference than a class or package. Listing 2.3 shows a sample interface and implementation.

Listing 2.3
start example
 interface IFlyingDevice { void whatAmI(); } class Plane implements IFlyingDevice { void whatAmI() { System.out.println( " am a plane"); } } class HotAirBalloon implements IFlyingDevice { void whatAmI() { System.out.println( "I am a hot air balloon"); } } class UserClass { void runProgram( IFlyingDevice device) { device.whatAmI(); } } 
end example

In Listing 2.3, the interface IFlyingDevice represents an interface that will be used elsewhere. Two classes, Plane and HotAirBalloon, implement the interface IFlyingDevice. The implementation of the method whatAmI is different in each case. The class UserClass has a single method, runProgram, which is passed in an instance of the interface IFlyingDevice . Within the implementation of the method runProgram , the interface method whatAmI is called. The question is which version of the method whatAmI will be called? The answer is that it is entirely unknown. The answer depends on whether the class Plane or HotAirBalloon has been instantiated . You can't figure that out from Listing 2.3.

What should be evident from the example in Listing 2.3 is that you can generically define an interface and then have multiple implementations of the interface. Generally, the purpose of the interface is to define an intention of action. For example, an intention could be to save data somewhere. Then, an implementation of the intention would be to save the data on a hard disk; another implementation could be to save data on a network.

Web Service-Level Granularization

This level of granularization did not exist until very recently. Using a Web Service is similar to using a Java Remote Method Invocation (RMI) call because both involve communication over a network between a client application and a server service. The difference with a Web Service is that it is based on XML, which is not object oriented; rather, it is a mixture of object-oriented and structure-oriented data. The advantage of a Web Service is that it is generic and can be used by any type of client, regardless of platform and technology. However, exposing a Web Service is not like exposing an interface or a class, even though the Java mappings make it possible.

Generic-Level Granularization, the Half Level

This level of granularization does not exist, except in the alpha versions (at the time of this writing) of the Java Software Development Kit (SDK). It is a half-level granularization because generics are useful helper functions that simplify specific aspects of Java programming. Generics are very similar to templates from the C++ world. The motivation for generics can easily be described by Listing 2.4.

Listing 2.4
start example
 class GenericType { public synchronized Object get(int index) { return null; } } 
end example

In Listing 2.4, the method returns an Object type. The data type Object is not a specific object but rather a generic object and the base of all other objects. Object is returned because in Java, if generics don't return a specific data type, more code needs to be written. For example, the core Java class Vector would have to be rewritten for each data type. If we rewrote Listing 2.4 to use generics, we would get Listing 2.5.

Listing 2.5
start example
 class GenericType< A> { public synchronized A get(int index) { return null; } } 
end example

In Listing 2.5, the class is defined using a generic data type A , which is referenced within the context of the class. The definition of A is like the declaration of a variable, except the declaration is not a variable but a data type. In addition, in places where data types are defined, you can use the declaration A . It is a very effective way of writing type-safe code, as shown by Listing 2.6.

Listing 2.6
start example
 GenericType< IFlyingDevice> variable; 
end example

In Listing 2.6, the interface IFlyingDevice replaces wherever the data type A is defined in Listing 2.5. Therefore, it would seem that generics solve the type problem very well. Generics are covered in more detail at the end of this chapter in the section entitled Generics .

Applied Software Engineering Using Apache Jakarta Commons
Applied Software Engineering Using Apache Jakarta Commons (Charles River Media Computer Engineering)
ISBN: 1584502460
EAN: 2147483647
Year: 2002
Pages: 109 © 2008-2017.
If you may any questions please contact us: