📄 lib0107.html
字号:
<html>
<META http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
<head>
<title>Making Components Easy to Use</title>
<link rel="STYLESHEET" type="text/css" href="images/xpolecat.css">
<link rel="STYLESHEET" type="text/css" href="images/ie.content.css">
</head>
<body>
<table width="100%" border="0" cellspacing="0" cellpadding="0">
<tr><td><div STYLE="MARGIN-LEFT: 0.15in;"><a href="toc.html"><img src="images/teamlib.gif" width="62" height="15" border="0" align="absmiddle" alt="Team LiB"></a></div></td>
<td align="right"><div STYLE="MARGIN-LEFT: 0.15in;">
<a href="LiB0106.html"><img src="images/previous.gif" width="62" height="15" border="0" align="absmiddle" alt="Previous Section"></a>
<a href="LiB0108.html"><img src="images/next.gif" width="41" height="15" border="0" align="absmiddle" alt="Next Section"></a>
</div></td></tr></table>
<br>
<div class="chapter">
<a name="ch16"></a>
<div class="section">
<h2 class="first-section-title"><a name="517"></a><a name="ch16lev1sec2"></a>Making Components Easy to Use</h2><p class="first-para">If you're evaluating component software, ease of use should be one of the deciding criteria. If you're creating an architectural component, there are a number of things you can do (that many component developers don't do) to make your component easy to use.</p>
<p class="para">
<b class="bold">Limit the instructions for basic tasks to a one-page cheat sheet.</b> You can have a more detailed document for sophisticated, unusual tasks. The longer the material developers need to read to get going, the higher the percentage of developers who will give up in the process and look for something else.</p>
<p class="para">
<b class="bold">Minimize the number of statements necessary to perform basic tasks.</b> One of the chief benefits to using a component is eliminating code in the application. A one-line call is ideal because it eliminates typing and reduces the number of classes and methods you need to learn.</p>
<p class="para">Consider the JAXB API as an example. A handful of lines must be issued to parse an XML document, as illustrated in <a class="internaljump" href="#ch16list01">listing 16.1</a>.</p>
<div class="example">
<span class="example-title"><span class="example-titlelabel">Listing 16.1: </span>Sample JAXB Parse</span><a name="518"></a><a name="ch16list01"></a>
<div class="formalbody">
<table class="BlueLine" border="0" cellspacing="0" cellpadding="0" width="100%">
<tr>
<td bgcolor="000080" class="bluecell"><font size="2" face="Arial" color="010100"><b><img src="_.gif" width="1" height="2" alt="Start example" border="0"></b></font></td>
</tr>
</table>
<pre class="literallayout">
<span class="unicode">…………</span> // some code omitted.
InputStream xmlDocumentInputStream = new FileInputStream
( "PurchaseOrder.xml" );
JAXBContext jc = JAXBContext.newInstance
( "book.sample.dao.xml.po" );
Unmarshaller u = jc.createUnmarshaller();
CustomerOrderList order =
(CustomerOrderList) u.unmarshal( xmlDocumentInputStream );
</pre>
<table class="BlueLine" border="0" cellspacing="0" cellpadding="0" width="100%">
<tr>
<td bgcolor="000080" class="bluecell"><font size="2" face="Arial" color="010100"><b><img src="_.gif" width="1" height="2" alt="End example" border="0"></b></font></td>
</tr>
</table>
<table class="BlankSpace" border="0" cellspacing="0" cellpadding="0" width="100%">
<tr>
<td height="16"></td>
</tr>
</table>
</div>
</div>
<p class="para">This series of calls could (and should) have been reduced to a one-line <a name="519"></a><a name="IDX-214"></a>call. Using CementJ, <a class="internaljump" href="#ch16list02">listing 16.2</a> performs the same parse with relatively simple code.</p>
<div class="example">
<span class="example-title"><span class="example-titlelabel">Listing 16.2: </span>Sample JAXB Parse Using CementJ</span><a name="520"></a><a name="ch16list02"></a>
<div class="formalbody">
<table class="BlueLine" border="0" cellspacing="0" cellpadding="0" width="100%">
<tr>
<td bgcolor="000080" class="bluecell"><font size="2" face="Arial" color="010100"><b><img src="_.gif" width="1" height="2" alt="Start example" border="0"></b></font></td>
</tr>
</table>
<pre class="literallayout">
<span class="unicode">…………</span> // some code omitted.
CustomerOrderList order =
(CustomerOrderList) JAXBUtility.getJaxbXmlObject
("book.sample.dao.xml.po",
new File("PurchaseOrder.xml") );
</pre>
<table class="BlueLine" border="0" cellspacing="0" cellpadding="0" width="100%">
<tr>
<td bgcolor="000080" class="bluecell"><font size="2" face="Arial" color="010100"><b><img src="_.gif" width="1" height="2" alt="End example" border="0"></b></font></td>
</tr>
</table>
<table class="BlankSpace" border="0" cellspacing="0" cellpadding="0" width="100%">
<tr>
<td height="16"></td>
</tr>
</table>
</div>
</div>
<p class="para">The authors of the JAXP API could have provided a one-line call to transform an XML document. Instead, they force people to learn about <span class="fixed">JAXBContext</span> and <span class="fixed">Unmarshaller</span>, classes that contain features most developers rarely use.</p>
<p class="para">One way to achieve a one-line call is to rely on a static method. This eliminates having to instantiate anything. The choice to make that call static is more than just a tactical choice. If you instantiated an object with the <span class="fixed">getJaxbXmlObject()</span> method on it, you would not benefit from the fact that it was an object. For instance, you probably would not put the object in some type of collection or pass it between other objects as a method argument.</p>
<p class="para">
<b class="bold">Minimize the number of arguments necessary to perform basic tasks.</b> You can accomplish this by providing multiple overloads. Some of those overloads have small numbers of arguments with sensible defaults for the rest. For example, consider ThreadWorks, an API that makes multithreaded programming in Java easier and safer. Software and documentation for ThreadWorks are available at <a target="_top" class="url" href="http://sourceforge.net/projects/threadworks/">http://sourceforge.net/projects/threadworks/</a>.</p>
<p class="para">The <span class="fixed">TaskManager</span> from ThreadWorks hides the complexity of threading code, running tasks for you, on your behalf. A simple example is the following code, which asynchronously runs one or more tasks:</p>
<div class="informalexample">
<pre class="literallayout">
_taskManager.run(task); // Run One Task
_taskManager.run(taskCollection); // Run several Tasks
_taskManager.run(taskArray); // Run several Tasks
</pre>
</div>
<p class="para">Optionally, you can run one or more tasks and have a <span class="fixed">Completion-EventListener</span> execute when all are done, as follows:</p>
<div class="informalexample">
<pre class="literallayout">
_taskManager.run(task, completionEventListener);
_taskManager.run(taskCollection, completionEventListener);
_taskManager.run(taskArray, completionEventListener);
<a name="521"></a><a name="IDX-215"></a>
</pre>
</div>
<p class="para">With <span class="fixed">TaskManager</span>, it should be easy to perform a basic task, yet advanced capabilities can be made available.</p>
<p class="para">
<b class="bold">Separate the classes meant for public consumption from those needed</b> <b class="bold">internally by the API.</b> The more classes a component has, the longer it takes to find the class with the functionality you want. For example Struts' <span class="fixed">org.apache.struts.action</span> package has three or four classes that are commonly used, and the rest are internal. Keeping all these classes together just adds to the time required to learn the API.</p>
<p class="para">One way to solve this problem is to move classes not meant for public consumption to a separate package that's documented as "for internal use only." For example, ThreadWorks separates all internal classes into its <span class="fixed">com.dvt.support</span> package. Users don't have to wade through low-level classes they don't need yet to find the functionality they want.</p>
<p class="para">
<b class="bold">Provide samples that are easy to copy with an index.</b> Make it easy to find a sample that is close to what the user wants. Most of us learn by example and don't type very quickly. Having something to copy from saves users time. A good place for short samples is within the JavaDoc.</p>
<p class="para">
<b class="bold">Limit dependencies on other APIs.</b> I once was forced to implement a poorly written scheduling component for a client (I wasn't given a choice). This component used two internal components that were hard to use and complex to configure. I've since learned how to avoid inflicting the same kind of pain on users of my open source components: use interfaces to decouple.</p>
<p class="para">For example, CementJ depends on logging services in several places. Users wanting to try out the API should not have to configure logging services or use a specific logging package. With a logging interface that decouples, CementJ implements a console logger by default. Users can easily use Log4J or the logging package that comes with version 1.4 and above of the JDK. Alternatively, CementJ can be configured to use any logger.</p>
<p class="para">Apache has a similar package for its open source Commons components. Called Logging, the package is a bit more complex and requires a bit more of a learning curve than CementJ. It can be downloaded from <a target="_top" class="url" href="http://jakarta.apache.org/commons/logging.html">http://jakarta.apache.org/commons/logging.html</a>.</p>
<p class="para">
<b class="bold">Check all arguments on all methods meant for public consumption and</b> <b class="bold">produce clear error messages for invalid inputs.</b> Rather than degenerating into derivative exceptions (e.g., null pointer exceptions), put information on how to correct problems in the exceptions. For example, "Invalid format <a name="522"></a><a name="IDX-216"></a>type argument" isn't as useful as "Invalid format type 'foo.' Valid types are the following constants on this class: PDF, HTML, XLS, and DOC." Simply displaying the erroneous value passed to a method might shorten the time it takes to debug and correct the issue.</p>
<p class="last-para">
<b class="bold">Avoid throwing "checked" exceptions.</b> Throwing "unchecked" exceptions, which extend <span class="fixed">RuntimeException</span>, is preferred because it doesn't force the user into as much try/catch logic. Not needing as much code to use a component definitely makes it easier to use. For a more detailed discussion of this rather controversial concept, see <a href="LiB0111.html#536" target="_parent" class="chapterjump">chapter 17</a>.</p>
</div>
</div><br>
<table width="100%" border="0" cellspacing="0" cellpadding="0">
<tr><td><div STYLE="MARGIN-LEFT: 0.15in;"><a href="toc.html"><img src="images/teamlib.gif" width="62" height="15" border="0" align="absmiddle" alt="Team LiB"></a></div></td>
<td align="right"><div STYLE="MARGIN-LEFT: 0.15in;">
<a href="LiB0106.html"><img src="images/previous.gif" width="62" height="15" border="0" align="absmiddle" alt="Previous Section"></a>
<a href="LiB0108.html"><img src="images/next.gif" width="41" height="15" border="0" align="absmiddle" alt="Next Section"></a>
</div></td></tr></table>
</body></html>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -