• Write Code that Declares, Implements, and/or Extends Interfaces
• Choose Between Interface Inheritance and Class Inheritance
• Apply Cohesion, Low-Coupling, IS-A, and HAS-A Principles
• Apply Object Composition Principles (Including HAS-A Relationships)
• Design a Class Using the Singleton Design Pattern
• Write Code to Implement the DAO Pattern
• Design and Create Objects Using a Factory and Use Factories from the API
Two-Minute Drill
Q&A Self Test
You were introduced to object-oriented (OO) principles in Chapter 2. We will be looking at some more advanced principles here, including coupling and cohesion. You’ll also learn what a design pattern is and dip your toe into the world of patterns by exploring three of them. As a bit of a teaser, a design pattern is a reusable solution to problems. Which will come in handy so you aren’t reinventing new ways to solve common problems.
3.3 Apply cohesion, low-coupling, IS-A, and HAS-A principles.
3.4 Apply object composition principles (including HAS-A relationships).
You learned the difference between IS-A and HAS-A in Chapter 2. As a brief review, how many IS-A/HAS-A statements can you write about BeachUmbrella
?
We can make four statements about BeachUmbrella
:
BeachUmbrella
IS-A Umbrella
BeachUmbrella
IS-A SunProtector
BeachUmbrella
HAS-A Stand
And, of course, as always,
BeachUmbrella
IS-A Object
In a nutshell, IS-A happens when a class uses inheritance—e.g., when a class extends another class or implements an interface. HAS-A happens when a class has instance variables of a class.
We’re going to admit it up front: The Oracle exam’s definitions for cohesion and coupling are somewhat subjective, so what we discuss in this chapter is from the perspective of the exam and is by no means The One True Word on these two OO design principles. It may not be exactly the way that you’ve learned it, but it’s what you need to understand to answer the questions. You’ll have very few questions about coupling and cohesion on the real exam.
These two topics, coupling and cohesion, have to do with the quality of an OO design. In general, good OO design calls for loose coupling and shuns tight coupling, and good OO design calls for high cohesion and shuns low cohesion. As with most OO design discussions, the goals for an application are
Ease of creation
Ease of maintenance
Ease of enhancement
Let’s start by attempting to define coupling. Coupling is the degree to which one class knows about another class. If the only knowledge that class A has about class B is what class B has exposed through its interface, then class A and class B are said to be loosely coupled… that’s a good thing. If, on the other hand, class A relies on parts of class B that are not part of class B’s interface, then the coupling between the classes is tighter… not a good thing. In other words, if A knows more than it should about the way in which B was implemented, then A and B are tightly coupled.
Using this second scenario, imagine what happens when class B is enhanced. It’s quite possible that the developer enhancing class B has no knowledge of class A—why would she? Class B’s developer ought to feel that any enhancements that don’t break the class’s interface should be safe, so she might change some noninterface part of the class, which then causes class A to break.
At the far end of the coupling spectrum is the horrible situation in which class A knows non-API stuff about class B, and class B knows non-API stuff about class A—this is REALLY BAD. If either class is ever changed, there’s a chance that the other class will break. Let’s look at an obvious example of tight coupling that has been enabled by poor encapsulation.
All nontrivial OO applications are a mix of many classes and interfaces working together. Ideally, all interactions between objects in an OO system should use the APIs—in other words, the contracts of the objects’ respective classes. Theoretically, if all of the classes in an application have well-designed APIs, then it should be possible for all interclass interactions to use those APIs exclusively. As we discussed in Chapter 2, an aspect of good class and API design is that classes should be well encapsulated.
The bottom line is that coupling is a somewhat subjective concept. Because of this, the exam will test you on really obvious examples of tight coupling; you won’t be asked to make subtle judgment calls.
While coupling has to do with how classes interact with each other, cohesion is all about how a single class is designed. The term cohesion is used to indicate the degree to which a class has a single, well-focused purpose. Keep in mind that cohesion is a subjective concept. The more focused a class is, the higher its cohesiveness—a good thing. The key benefit of high cohesion is that such classes are typically much easier to maintain (and less frequently changed) than classes with low cohesion. Another benefit of high cohesion is that classes with a well-focused purpose tend to be more reusable than other classes. Let’s look at a pseudo-code example:
Now imagine your manager comes along and says, “Hey, you know that accounting application we’re working on? The clients just decided that they’re also going to want to generate a revenue projection report, oh and they want to do some inventory reporting also. They do like our reporting features, however, so make sure that all of these reports will let them choose a database, choose a printer, and save generated reports to data files….” Ouch!
Rather than putting all the printing code into one report class, we probably would have been better off with the following design right from the start:
This design is much more cohesive. Instead of one class that does everything, we’ve broken the system into four main classes, each with a very specific, or cohesive, role. Because we’ve built these specialized, reusable classes, it’ll be much easier to write a new report since we already have the database connection class, the printing class, and the file saver class, and that means they can be reused by other classes that might want to print a report.
3.4 Apply object composition principles.
Object composition principles build on IS-A and HAS-A. If you aren’t 100 percent comfortable with the differences between IS-A and HAS-A, go back and reread Chapter 2 before continuing on.
Object composition refers to one object having another as an instance variable (HAS-A). Sometimes, that instance variable might be the same type as the object we are writing. Think about when you get that package from Amazon that is a box containing some bubble wrap, a receipt, and yet another box. That is composition at work. The outer (containing class) box contains an inner (instance) box.
Let’s build out this box example. We want to reuse as much code as possible. After all, the procedure for sealing a box with some tape doesn’t change from box to box. Let’s start with the concept of a Box
:
Wait. Boxes are simple. Why do we need an interface? We realize there are many types of boxes. There are gift boxes, jewelry boxes, small boxes, large boxes, etc. Now we create a concrete type of Box
:
GiftBox
implements Box
by implementing the two methods Box
requires. Providing an interface lets us keep the Box
logic where it belongs—in the relevant subclasses. And to review, GiftBox
IS-A Box
.
Now that we’ve figured out Box
, it’s time to build a MailerBox
:
See any problems? That’s right, we’ve duplicated the logic to pack and seal the Box
. All two lines of it. Our real Box
logic would be a lot longer, though. And when we start manufacturing different types of boxes, we’d have that Box
logic all over the place.
One thought is to solve this by having MailerBox
extend GiftBox
. It doesn’t take long to see the problem here. We would need MailerGiftBox
, MailerSmallBox
, MailerMediumBox
, etc. That’s a lot of classes! And this technique would repeat for other types of functionality we create. Which means we would also need WrappedGiftBox
, MailerWrappedGiftBox
. Uh oh. We can only extend one class in Java. We can’t inherit both Mailer
and GiftBox
functionality. Clearly, IS-A isn’t going to work for us here.
Instead, we can use HAS-A. First, we create the interface for our desired functionality:
Then we can create the object that is both a Box
and Mailer
:
The first thing to notice is that the logic to pack and seal a box is only in one place—in the Box
hierarchy where it belongs. In fact, the MailerBox
doesn’t even know what kind of Box
it has. This allows us to be very flexible.
Next, notice the implementation of pack()
and seal()
. That’s right—each is one line. We delegate to Box
to actually do the work. This is called method forwarding or method delegation. These two terms mean the same thing.
Finally, notice that MailerBox
is both a Box
and a Mailer
. This allows us to pass it to any method that needs a Box
or a Mailer
.
Looking at these classes graphically, we have the following:
Think about which of the objects can be passed to this method:
GiftBox
can because it implements Box
. So can MailerBox
for the same reason. MailerBox
knows how to pack—by delegating to the Box
instance. This is why it is important for the composing class to both contain and implement the same interface. Repeating the relevant parts here, we have:
You can see the composition part. MailerBox
both IS-A Box
and HAS-A Box
. MailerBox
is composed of a Box
and delegates to Box
for logic. That’s the terminology for object composition.
Benefits of composition include
Reuse An object can delegate to another object rather than repeating the same code.
Preventing a proliferation of subclasses We can have one class per functionality rather than needing one for every combination of functionalities.
3.5 Design a class using the singleton design pattern.
In a nutshell, the singleton design pattern ensures we only have one instance of a class of an object within the application. It’s called a creational design pattern because it deals with creating objects. But wait, what’s this “design pattern”?
Wikipedia currently defines a design pattern as “a general reusable solution to a commonly occurring problem within a given context.” What does that mean? As programmers, we frequently need to solve the same problem repeatedly. Such as how to only have one of a class of an object in the application. Rather than have everyone come up with their own solution, we use a “best practice” type solution that has been documented and proven to work. The word “general” is important. We can’t just copy and paste a design pattern into our code. It’s just an idea. We can write an implementation for it and put that in our code.
Using a design pattern has a few advantages. We get to use a solution that is known to work. The tradeoffs, if any, are well documented so we don’t stumble over problems that have already been solved. Design patterns also serve as a communication aid. Your boss can say, “We will use a singleton,” and that one word is enough to tell you what is expected.
When books or web pages document patterns, they do so using consistent sections. In this book, we have sections for the “Problem,” “Solution,” and “Benefits.” The “Problem” section explains why we need the pattern—what problem we are trying to solve. The “Solution” section explains how to implement the pattern. The “Benefits” section reviews why we need the pattern and how it has helped us solve the problem. Some of the benefits are hinted at in the “Problem” section. Others are additional benefits that come from the pattern.
While the exam only covers three patterns, this is just to get your feet wet. Whole books are written on the topic of design patterns. Head First Design Patterns (O’Reilly Media, 2004) covers more patterns. And the most famous book on patterns, Design Patterns: Elements of Reusable Object-Oriented Software (Addison-Wesley Professional, 1994)—also known as “Gang of Four”—covers 23 design patterns. You may notice that these books are over 10 years old. That’s because the classic patterns haven’t changed.
While each book does use a consistent set of sections, there isn’t one common set of names. You will see synonyms used such as “Problem” versus “Motivation.” You will also see additional sections such as “Consequences.” The exam picks simpler patterns so you can use the simpler sections.
When talking about patterns, they are usually presented in a problem/solution format. Then, depending on the level of detail, other sections are added. In this book, each pattern will cover the problem, solution, and benefits.
Let’s suppose we are going to put on a show. We have one performance of this show and we only have a few seats in the theater.
This code prints out true
twice. That’s a problem. We just put two people in the same seat. Why? We created a new Show
object every time we needed it. Even though we want to use the same theater and seats, Show
deals with a new set of seats each time. Which causes us to double-book seats.
There are a few ways to implement the singleton pattern. The simplest is
Now the code prints true
and false
. Much better! We are no longer going to have two people in the same seat. The bolded bits in the code call attention to the implementation of the singleton pattern.
The key parts of the singleton pattern are
A private static variable to store the single instance called the singleton. This variable is usually final to keep developers from accidentally changing it.
A public static method for callers to get a reference to the instance.
A private constructor so no callers can instantiate the object directly.
Remember, the code doesn’t create a new Show
each time, but merely returns the singleton instance of Show
each time getInstance()
is called.
To understand this a little better, consider what happens if we change parts of the code.
If the constructor weren’t private, we wouldn’t have a singleton. Callers would be free to ignore getInstance()
and instantiate their own instances. Which would leave us with multiple instances in the program and defeat the purpose entirely.
If getInstance()
weren’t public, we would still have a singleton. However, it wouldn’t be as useful because only static methods of the class Show
would be able to use the singleton.
If getInstance()
weren’t static, we’d have a bigger problem. Callers couldn’t instantiate the class directly, which means they wouldn’t be able to call getInstance()
at all.
If INSTANCE
weren’t static and final, we could have multiple instances at different points in time. These keywords signal that we assign the field once and it stays that way for the life of the program.
When talking about design patterns, it is common to also communicate the pattern in diagram form. The singleton pattern diagram looks like this:
A format called UML (Unified Modeling Language) is used. The diagrams in this book use some aspects of UML, such as a box with three sections representing each class. Actual UML uses more notation, such as showing public versus private visibility. You can think of this as faux-UML.
As long as the method in the diagram keeps the same signature, we can change our logic to other implementations of the singleton pattern. One “feature” of the above implementation is that it creates the Show
object before we need it. This is called eager initialization, which is good if the object isn’t expensive to create or we know it will be needed for every run of the program. Sometimes, however, we want to create the object only on the first use. This is called lazy initialization.
In this case, INSTANCE
isn’t set to be a Show
until the first time getInstance()
is called. Walking through what happens, the first time getInstance()
is called, Java sees INSTANCE
is still null and creates the singleton. The second time getInstance()
is called, Java sees INSTANCE
has already been set and simply returns it. In this example, INSTANCE
isn’t final because that would prevent the code from compiling.
The singleton code here assumes you are only running one thread at a time. It is NOT thread-safe. Think about if this were a web site and two users managed to be booking a seat at the exact same time. If getInstance()
were running at the exact same time, it would be possible for both of them to see that INSTANCE was null and create a new Show
at the same time. There are a few ways to solve this. One is to add synchronized
to the getInstance()
method. This works, but comes with a small performance hit. We’re getting way beyond the scope of the exam, but you can Google “double checked locked pattern” for more information.
You might have noticed that the code for getInstance()
can get a bit complicated. In Java 5, there became a much shorter way of creating a singleton:
Short and sweet. By definition, there is only one instance of an enum constant. You are probably wondering why we’ve had this whole discussion of the singleton pattern when it can be written so easily. The main reason is that enums were introduced with Java 5 and there is a ton of older code out there that you need to be able to understand. Another reason is that sometimes the older versions of the pattern are still needed.
Benefits of the singleton pattern include the following:
The primary benefit is that there is only one instance of the object in the program. When an object’s instance variables are keeping track of information that is used across the program, this becomes useful. For example, consider a web site visitor counter. You only want one count that is shared.
Another benefit is performance. Some objects are expensive to create. For example, maybe we need to make a database call to look up the state for the object.
3.6 Write code to implement the DAO pattern.
DAO stands for “Data Access Object.” A DAO is only responsible for storing data. Nothing else. Why can’t we do this in the object with everything else, you ask?
Suppose we have three objects in our program as shown in Table 10-1.
TABLE 10-1 Object Responsibilities
Already there is a problem. These classes aren’t cohesive. Remember cohesion? We want each class to have a single purpose. Storing and searching objects in the database is NOT that purpose. Having that database code all over makes it hard to focus on the classes’ core purpose for existing, which is clearly for our entertainment. Since dealing with a database is very common, separating out that responsibility is a pattern—the DAO.
Let’s drill down into just the Book
class. This is the poorly written, noncohesive version. Pay particular attention to the two responsibilities.
Counting the getters and setters we didn’t want to bore you with, the Book
class is over 50 lines. And it hardly does anything! A real Book
class would have a lot more fields. A bookstore needs to tell you when the book was written, the edition, the price, and all sorts of other information. A bookstore also needs to be able to keep track of books somewhere other than a map. After all, we don’t want our bookstore to forget everything when we reboot.
The problem is that our class is responsible for two things. The first is keeping track of being a book. This seems like a good responsibility for a class to have that is named Book
. The other is keeping track of storage responsibilities.
A datastore is the name of—wait for it—where data is stored. In the real world, we’d use a database or possibly a file containing the books. For testing, we might use an in-memory database. The map in Book
is actually a bare-bones in-memory datastore. As you’ll see in Chapter 15, using a real database would make the Book
class MUCH longer.
This is a problem. We want our code to be easy to read and focused on one responsibility.
The DAO pattern has us split up these two responsibilities. We start by letting our Book
class focus on being a book:
There can be other methods in Book
such as toString()
, hashCode()
, and equals()
. These methods have to do with the Book
object. Methods that have to do with a bookstore or database are now gone. Much better. Now we can go on to the data access code:
The new InMemoryBookDao
class only knows how to do one thing—deal with the datastore. This is such a common technique that it has a name: the single responsibility principle. The method names in the DAO are actually standard. You’ll see them again when you get to Chapter 15.
When everything was in the Book
object, we just created a Book
and started calling methods. Now that Book
and DAO are separate objects, the caller deals with two objects:
The new DAO object gets all the calls that have to do with the datastore. Table 10-2 shows why each method call is associated with each class.
TABLE 10-2 DAO Method Call Associations
Good so far? The DAO pattern only has one more part. Our datastore is pretty wimpy right now. Every time we restart the program, it forgets what books we have. At some point, we are going to want to change that. But when we do, we want to make it easier for callers to change.
Since all the method names in the interface match our existing DAO, all we have to do is have it implement the new interface:
And we can use the interface type when declaring the DAO:
Wait a minute. We still have InMemoryBookDao
in the line of code that instantiates the DAO. It is a bit like writing Collection c = new ArrayList();
. It just so happens to be an ArrayList
right now, but we could change it at any time. It is a bit like signifying that the surrounding code shouldn’t get too cozy with any particular implementation. We can always change the specific DAO implementation later without changing the interface. And we will learn in the next section how to get rid of even the one reference to InMemoryBookDao
.
To review the classes involved in the DAO pattern, we have the following illustration:
Now we have three objects, each responsible for one thing. We have the public interface BookDao
, which specifies the contract. Next, we have the implementation of that interface, InMemoryBookDao
. Finally, we have the Book
class itself, which focuses on the object state and any methods related to Book
.
In addition to making the code easier to read, this pattern makes it easy for us to organize code. We could put all the JavaBeans in one package, the interfaces in another package, and the implementations in still another package. This approach allows us to have one package for in-memory implementations and another for JDBC implementations.
To review, the benefits of the DAO pattern are as follows:
The main object (
Book
in this case) is cohesive and doesn’t have database code cluttering it up.
All the database code is in one part of the program, making it easy to find.
We can change the database implementation without changing the business object.
Reuse is easier. As the database code grows, we can create helper classes and even helper superclasses.
3.7 Design and create objects using a factory and use factories from the API.
Like the singleton design pattern, the factory design pattern is a creational design pattern. Unlike the singleton, it doesn’t limit you to only having one copy of an object. The factory design pattern creates new objects of whatever implementation it chooses.
So far, we only have one implementation of our BookDAO
called InMemoryBookDao
. It isn’t very robust since it only stores objects in memory. We will need to create a version of it that uses JDBC or writes to a file or does something else where we can remember state. We want to be able to change the DAO implementation without having to change the caller code (Student
). Remember coupling? This is loose coupling. Interfaces are part of loose coupling, but we want to go a step further.
The simplest factory we can write while still implementing the pattern is an abstract class and implementation with one method:
This is very simple. The Factory
is an abstract class with one method. Its implementation simply returns an in-memory DAO. From Student
’s point of view, this is all that exists—the Factory
class and the BookDao
interface. Note that Student
no longer has the code new InMemoryBookDao
.
In diagram form, here is how our classes fit together:
To review, Student
only interacts with the two abstract classes Factory
and BookDao
. All implementation is in the concrete subclasses.
This setup frees us up to change the implementation of FactoryImpl
without affecting the caller.
Let’s try an example to show how we can change the factory. Suppose we write a DAO implementation OracleBookDao
that uses a real database. We might change FactoryImpl
to:
Just like that—nothing changes in Student
. Yet it starts using the real database implementation. This is good design. A change only needs to be made in one place.
You might be wondering why Factory
is an abstract class rather than an interface. It is common with the factory method pattern to work “around” the creation logic, or at least recognize that it might happen later.
As an example here, we could decide that we want to include the test logic check in the superclass so any future subclasses use it:
In this case, the superclass Factory
has all the common logic, and the subclass FactoryImpl
merely creates the relevant object. Notice how the API createDao()
hasn’t changed its signature at all despite our extensive changes to the method implementation. That is why we are using the factory pattern. So the caller Student
isn’t affected by any changes to our factory and DAO.
There are three patterns with factory in their name:
Factory
method This is the pattern we are talking about in this chapter and is on the exam.
Abstract factory This takes the factory method pattern a bit further and is used to create families of related classes.
Factory It’s debatable whether this is even a pattern. It’s not in the “Gang of Four” book. However, on the job, when developers say “factory,” they are often referring to a method like
public Foo createFoo() {return new Foo(); }
rather than a full-fledged factory method pattern. The method may return Foo
or SubclassOfFoo
, but it doesn’t have the superclass/subclass relationship for the creator object that the factory method pattern has.
You might have noticed we didn’t say anything about making the DAO constructors private. In the singleton pattern, we needed to force callers to use getInstance()
to prevent multiple copies. The factory pattern is merely a convenience. At times, it is a pretty big convenience. However, callers can still instantiate the DAO directly without breaking our logic, so we let them.
In fact, Oracle uses the factory pattern in the Java API in many places. When we learned how to create a DateFormat
, we used DateFormat.getInstance()
, DateFormat.getDateInstance()
, and other similar factory methods. If you wanted more control over the format string, you could still write new
SimpleDateFormat(“yyyy MM”)
. Oracle leaves the constructor available for when you need it.
Similarly, when we learned how to create a Calendar
, we wrote Calendar.getInstance()
or Calendar.getInstance(Locale)
. You will see many more examples of the factory pattern as you explore the Java API.
Benefits of the factory design pattern include the following
The caller doesn’t change when the factory returns different subclasses. This is useful when the final implementation isn’t ready yet. For example, maybe the database isn’t yet available. It’s also useful when we want to use different implementations for unit testing and production code. For example, you want to write code that behaves the same way, regardless of what happens to be in the database.
Centralizes creation logic outside the calling class. This prevents duplication and makes the code more cohesive.
Allows for extra logic in the object creation process. For example, an object is time-consuming to create, and you want to reuse the same one each time.
We started the chapter by reviewing the difference between IS-A and HAS-A. To review the review, IS-A is implemented using inheritance, and HAS-A is implemented using instance variables that refer to other objects.
We discussed the OO concepts of coupling and cohesion. Loose coupling is the desirable state of two or more classes that interact with each other only through their respective APIs. Tight coupling is the undesirable state of two or more classes that know inside details about another class, details not revealed in the class’s API. High cohesion is the desirable state of a single class whose purpose and responsibilities are limited and well focused.
Then we built on those concepts and learned about object composition principles. In particular, we learned how to build objects out of other objects. We saw how method delegation and method forwarding prevent the need to duplicate code. For example:
Next, we moved on to design patterns. We learned that design patterns are reusable solutions to common problems.
We saw the singleton pattern used to ensure we only have one instance of a given class within the application. We created a private static variable to store the single instance, which we called the singleton. We then created a public static method for callers to get a reference to the instance. Finally, we made the constructor private so no callers can instantiate the object directly.
We also looked at the DAO design pattern. DAO stands for Data Access Object and provides a way to separate database functionality from the main business object. We saw how using an interface allows us to easily change the data access implementation. A DAO interface typically looks like this:
Finally, we looked at the factory design pattern as another way of creating objects. We learned how to create an abstract and concrete factory object. We also saw that we could have common logic in the abstract class. For example:
Here are some of the key points from each certification objective in this chapter.
IS-A refers to inheritance.
IS-A is expressed with either the keyword
extends
or implements.
IS-A, “inherits from,” and “is a subtype of” are all equivalent expressions.
HAS-A means an instance of one class “has a” reference to an instance of another class or another instance of the same class.
Coupling refers to the degree to which one class knows about or uses members of another class.
Loose coupling is the desirable state of having classes that are well encapsulated, minimize references to each other, and limit the breadth of API usage.
Tight coupling is the undesirable state of having classes that break the rules of loose coupling.
Cohesion refers to the degree to which a class has a single well-defined role or responsibility.
High cohesion is the desirable state of a class whose members support a single well-focused role or responsibility.
Low cohesion is the undesirable state of a class whose members support multiple unfocused roles or responsibilities.
Object composition takes advantage of IS-A, HAS-A, and polymorphism.
Object composition prevents proliferation of subclasses by having each class responsible for one thing.
Object composition delegates to objects to which it “has” to implement functionality.
The terms method forwarding and method delegation are used interchangeably.
Design pattern is “a general reusable solution to a commonly occurring problem within a given context.”
Having only one instance of the object allows a program to share its state.
This pattern might improve performance by not repeating the same work.
This pattern often stores a single instance as a static variable.
We can instantiate right away (eager) or when needed (lazy).
DAO stands for Data Access Object.
DAO separates datastore responsibilities from the core responsibilities of the object.
DAO uses an interface so we can change the implementation.
DAO is only responsible for database operations. The main object remains cohesive.
DAO facilitates reuse.
Factory is a creational design pattern.
Factory can create any subclass of an interface or abstract class.
Factory
is an abstract class.
Factory subclassing allows for multiple factories.
The factory method return type is an interface or abstract class.
Factory method implementation returns subclasses of the target object.
There may be common logic in the abstract class that all factory subclasses share.
The following questions will help you measure your understanding of the material presented in this chapter. Read all of the choices carefully, as there may be more than one correct answer. Choose all correct answers for each question. Stay focused.
1. Given:
Which is true?
A. A
H
AS-A B
and A
HAS-A C
B. A
H
AS-A B and A
IS-A C
C. A
I
S-A B and A
HAS-A C
D. A
I
S-A B and A
IS-A C
E. B
I
S-A A
and A
-HAS-A C
F. B
I
S-A A and A
IS-A C
2. Which statements are true? (Choose all that apply.)
A. Method delegation relies on IS-A relationships
B. Method forwarding relies on HAS-A relationships
C. The DAO pattern limits you to one instance of the DAO object
D. The singleton pattern relies on IS-A relationships
E. To use object composition, classes must be final
3. Given:
Which design pattern or principle is implemented?
A. Coupling
B. DAO
D. IS-A
E. Object composition
F. Singleton
4. Given:
Which design pattern or principle is implemented?
A. DAO
B. Factory
C. IS-A
D. Object composition
E. Singleton
5. Given:
Which design pattern or principle is implemented?
A. DAO
B. Factory
C. IS-A
D. Object composition
E. Singleton
6. Which design patterns are classified as creational design patterns? (Choose all that apply.)
A. Coupling
B. DAO
C. Factory
D. IS-A
E. Object composition
F. Singleton
7. Which statements indicate the need to use the factory pattern? (Choose all that apply.)
A. You don’t want the caller to depend on a specific implementation
B. You have two classes that do the same thing
C. You only want one instance of the object to exist
D. You want one class to be responsible for database operations
E. You want to build a chain of objects
8. Given:
And the following statements:
I – This is a good use of the DAO pattern
II – The DAO needs an interface
III – The DAO is missing a method
IV – The DAO must use a type other than String
Which of these statements are true?
A. Statement I only
B. Statement II only
C. Statement III only
D. Statement IV only
E. Statements II and III
F. Statements III and IV
9. Which is a benefit of the DAO pattern? (Choose all that apply.)
A. Reuse is easier
B. The database code is automatically generated
C. We can change the database implementation independently
D. Your business object extends the DAO pattern to reduce coding
E. You are limited to one DAO object
10. Which are true of design patterns? (Choose all that apply.)
A. Design patterns are chunks of code you can copy into your application unchanged
B. Design patterns are conceptual reusable solutions
C. Design patterns are shortcuts to talking about code
D. There are three design patterns defined for Java
E. You can only use each design pattern once per application
F. Design patterns are libraries you can call from your code
11. Which statement is true? (Choose all that apply.)
A. Cohesion is the OO principle most closely associated with hiding implementation details
B. Cohesion is the OO principle most closely associated with making sure that classes know about other classes only through their APIs
C. Cohesion is the OO principle most closely associated with making sure that a class is designed with a single well-focused purpose
D. Cohesion is the OO principle most closely associated with allowing a single object to be seen as having many types
12. Given:
1) ClassA
has a ClassD
2) Methods in ClassA
use public methods in ClassB
3) Methods in ClassC
use public methods in ClassA
4) Methods in ClassA
use public variables in ClassB
Which is most likely true? (Choose only one.)
A. ClassD
has low cohesion.
B. ClassA
has weak encapsulation.
C. ClassB
has weak encapsulation.
D. ClassB
has strong encapsulation.
E. ClassC
is tightly coupled to ClassA
.
1. C is correct. Since
A
extends B
, it IS-A B
. Since C
is an instance variable in A
, A
HAS-A C
.
A, B, D, E, and F are incorrect because of the above. (OCP Objective 3.3)
2. B is correct. Method forwarding is an object composition principle and calls methods on an instance variable of an object.
A is incorrect because method delegation and method forwarding are the same thing. C is incorrect because it is the singleton pattern that limits you to one object. D is incorrect because singleton classes typically don’t have a superclass (other than
Object
). E is incorrect because there is no such requirement. (OCP Objective 3.4)
3. F is correct. The singleton pattern is identifiable by the static variable for the single instance and the accessor returning it.
B is incorrect because there is no interface. The class just happens to have methods
update()
and delete()
, which are similar to those found in a DAO. A, C, D, and E are incorrect because of the above. (OCP Objective 3.5)
4. D is correct. The object composition principle of method forwarding is shown.
E is tricky, but incorrect. Although
getInstance()
is a common name for a method in a singleton, the method doesn’t return a static object. While it does create an object, it isn’t a factory either, since there is no superclass. A, B, and C are incorrect because of the above. (OCP Objective 3.4)
5. B is correct. Class A is the object we are creating using the factory method. Class G is the abstract superclass for the factory. Not shown is a class implementing class G that actually creates the object.
A, C, D,and E are incorrect because of the above. (OCP Objective 3.7)
6. C and F are correct. The factory design pattern creates new objects for each call, and the singleton design pattern creates one object, returning it each time.
A, B, D, and E are incorrect because of the above. (OCP Objectives 3.5 and 3.7)
7. A is correct. The factory design pattern decouples the caller from the implementation class name.
B is incorrect because that would be poor design. C is incorrect because it describes the singleton pattern. D is incorrect because it describes the DAO pattern. E is incorrect because of the above. (OCP Objective 3.7)
8. B is correct. The Data Access Object pattern uses an interface so callers aren’t dependent on a specific implementation class.
A, C, D, E, and F are incorrect because of the above. (OCP Objective 3.6)
9. A and C are correct. The DAO pattern centralizes logic for the data access code, making reuse easier and allowing you to switch out implementations.
B is incorrect because you still have to code the DAO. D is incorrect because you call a DAO from your business object; you do not inherit from it. E is incorrect because you can have many DAO objects. (OCP Objective 3.6)
10. B and C are correct. Design patterns are conceptual and design level. You have to code the implementation for each use.
D is incorrect because there are dozens of patterns defined for Java. Only three of them are tested on the exam, but you should be aware that more exist. E is incorrect because it makes sense to reuse the same pattern. For example, you might have multiple DAO objects. A and F are incorrect because of the above. (OCP Objectives 3.5, 3.6, and 3.7)
11. C is correct.
A, B, and D are incorrect. A refers to encapsulation, B refers to coupling, and D refers to polymorphism. (OCP Objective 3.3)
12. C is correct. Generally speaking, public variables are a sign of weak encapsulation.
A, B, D, and E are incorrect because based on the information given, none of these statements can be supported. (OCP Objective 3.3)