﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>BlogJava-无为-随笔分类-设计模式</title><link>http://www.blogjava.net/mlh123caoer/category/7464.html</link><description>无为则可为，无为则至深！
</description><language>zh-cn</language><lastBuildDate>Sat, 15 Sep 2007 10:35:47 GMT</lastBuildDate><pubDate>Sat, 15 Sep 2007 10:35:47 GMT</pubDate><ttl>60</ttl><item><title>依赖注入和单元测试</title><link>http://www.blogjava.net/mlh123caoer/archive/2007/09/14/145190.html</link><dc:creator>草儿</dc:creator><author>草儿</author><pubDate>Fri, 14 Sep 2007 09:07:00 GMT</pubDate><guid>http://www.blogjava.net/mlh123caoer/archive/2007/09/14/145190.html</guid><wfw:comment>http://www.blogjava.net/mlh123caoer/comments/145190.html</wfw:comment><comments>http://www.blogjava.net/mlh123caoer/archive/2007/09/14/145190.html#Feedback</comments><slash:comments>3</slash:comments><wfw:commentRss>http://www.blogjava.net/mlh123caoer/comments/commentRss/145190.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/mlh123caoer/services/trackbacks/145190.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 也许在各位读者眼里，依赖注入和框架Spring等同的。其实依赖注入是一个可以在容器外使用的OO开发概念。同时，依赖注入（Dependency Injection）对于单元测试<br>也很有用。在该篇blog中，我们可以了解到：<br><br>    * 什么是依赖注入（Dependency Injection）<br>    * 如何保证类和依赖注入友好性<br>    * 依赖注入有助于单元测试<br>&nbsp;&nbsp;<a href='http://www.blogjava.net/mlh123caoer/archive/2007/09/14/145190.html'>阅读全文</a><img src ="http://www.blogjava.net/mlh123caoer/aggbug/145190.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/mlh123caoer/" target="_blank">草儿</a> 2007-09-14 17:07 <a href="http://www.blogjava.net/mlh123caoer/archive/2007/09/14/145190.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Fuzz testing</title><link>http://www.blogjava.net/mlh123caoer/archive/2007/01/12/93403.html</link><dc:creator>草儿</dc:creator><author>草儿</author><pubDate>Fri, 12 Jan 2007 05:28:00 GMT</pubDate><guid>http://www.blogjava.net/mlh123caoer/archive/2007/01/12/93403.html</guid><wfw:comment>http://www.blogjava.net/mlh123caoer/comments/93403.html</wfw:comment><comments>http://www.blogjava.net/mlh123caoer/archive/2007/01/12/93403.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/mlh123caoer/comments/commentRss/93403.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/mlh123caoer/services/trackbacks/93403.html</trackback:ping><description><![CDATA[<p>Level: Intermediate</p>
		<p>
				<a href="http://www-128.ibm.com/developerworks/java/library/j-fuzztest.html#author">
						<font color="#996699">Elliotte Harold</font>
				</a> (<a href="mailto:elharo@metalab.unc.edu?subject=Fuzz testing&amp;cc=dwxed@us.ibm.com"><font color="#5c81a7">elharo@metalab.unc.edu</font></a>), Adjunct Professor, Polytechnic University<br /></p>
		<p>26 Sep 2006<br /></p>
		<blockquote>Fuzz testing is a simple technique that can have a profound effect on your code quality. In this article, Elliotte Rusty Harold shows what happens when he deliberately injects random bad data into an application to see what breaks. He also explains how to use defensive coding techniques such as checksums, XML data storage, and code verification to harden your programs against random data. He concludes with an exercise in thinking like a code cracker -- a crucial technique for defending your code.</blockquote>
		<!--START RESERVED FOR FUTURE USE INCLUDE FILES-->
		<script language="JavaScript" type="text/javascript">
				<!--
if (document.referrer&&document.referrer!="") { 
   // document.write(document.referrer);
   var q = document.referrer;
   var engine = q;
   var isG = engine.search(/google\.com/i);
   var searchTerms;
   //var searchTermsForDisplay;
   if (isG != -1) { 
	   var i = q.search(/q=/);
	   var q2 = q.substring(i+2);
	   var j = q2.search(/&/);
	   j = (j == -1)?q2.length:j;
	   searchTerms = q.substring(i+2,i+2+j);
	   if (searchTerms.length != 0) {
	       searchQuery(searchTerms);
	       document.write("<div id=\"contents\"></div>");
	   }
   } 
}
//-->
		</script>
		<!--END RESERVED FOR FUTURE USE INCLUDE FILES-->
		<p>For years, I've been astounded by the number of corrupt files that can crash Microsoft Word. A few bytes out of place and the whole application goes down in flames. On older, non-memory-protected operating systems, the whole computer usually went down with it. Why can't Word recognize when it's received bad data and simply put up an error message? Why does it corrupt its own stack and heap just because a few bits got twiddled? Of course, Word is hardly the only program that behaves atrociously in the face of malformed files. </p>
		<p>This article introduces you to a technique that attempts to avert just this sort of disaster. In fuzz testing, you attack a program with random bad data (aka <i>fuzz</i>), then wait to see what breaks. The trick of fuzz testing is that it isn't logical: Rather than attempting to guess what data is likely to provoke a crash (as a human tester might do), an automated fuzz test simply throws as much random gibberish at a program as possible. The failure modes identified by such testing usually come as a complete shock to programmers because no logical person would ever conceive of them.</p>
		<p>Fuzz testing is a simple technique, but it can nonetheless reveal important bugs in your programs. It can identify real-world failure modes and signal potential avenues of attack that should be plugged before your software ships. </p>
		<p>
				<a name="N10067">
						<span class="atitle">How fuzz testing works</span>
				</a>
		</p>
		<p>Fuzz testing is a very simple procedure to implement:</p>
		<ol>
				<li>Prepare a correct file to input to your program. 
</li>
				<li>Replace some part of the file with random data. 
</li>
				<li>Open the file with the program. 
</li>
				<li>See what breaks. </li>
		</ol>
		<p>You can vary the random data in any number of ways. For example, you might randomize the entire file rather than replacing just a part of it. You could limit the file to ASCII text or non-zero bytes. Any way you slice it, the key is to throw a lot of random data at an application and see what fails. </p>
		<p>
		</p>
		<table cellspacing="0" cellpadding="0" width="40%" align="right" border="0">
				<tbody>
						<tr>
								<td width="10">
										<img height="1" alt="" src="http://www.ibm.com/i/c.gif" width="10" />
								</td>
								<td>
										<table cellspacing="0" cellpadding="5" width="100%" border="1">
												<tbody>
														<tr>
																<td bgcolor="#eeeeee">
																		<a name="N10085">
																				<b>Testing C-based applications</b>
																		</a>
																		<br />Many programs written in C have trouble when strings contain extra zeroes -- so much so that extra zeroes can completely hide other problems in the code. Once you've identified a program's problems with zero-bytes, you might wish to remove them to allow other problems to surface. </td>
														</tr>
												</tbody>
										</table>
								</td>
						</tr>
				</tbody>
		</table>
		<p>While you can do initial tests manually, you should really automate fuzzing for maximum effect. In this case, you first need to define the proper error behavior for the application when faced with corrupt input. (If you discover the program hasn't bothered to define what happens when the input data is corrupt, well, there's your first bug.) Then you simply pass random data into the program until you find a file that doesn't trigger the proper error dialog, message, exception, etc. Store and log that file so you can reproduce the problem later. Repeat.</p>
		<p>Although fuzz testing usually requires some manual coding, there are tools that can help. For example, Listing 1 shows a simple Java™ class that randomly modifies a certain length of a file. I usually like to start fuzzing somewhere after the first few bytes because programs seem more likely to notice an early mistake than a later one. (You want to find the errors the program doesn't check, not the ones it does.)</p>
		<p>
				<br />
				<a name="listing1">
						<b>Listing 1. A class that replaces part of a file with random data</b>
				</a>
				<br />
		</p>
		<table cellspacing="0" cellpadding="0" width="100%" border="0">
				<tbody>
						<tr>
								<td class="code-outline">
										<pre class="displaycode">import java.io.*;
import java.security.SecureRandom;
import java.util.Random;

public class Fuzzer {

     private Random random = new SecureRandom();
     private int count = 1;

     public File fuzz(File in, int start, int length) throws IOException  
{

         byte[] data = new byte[(int) in.length()];
         DataInputStream din = new DataInputStream(new FileInputStream(in));
         din.readFully(data);
         fuzz(data, start, length);
         String name = "fuzz_" + count + "_" + in.getName();
         File fout = new File(name);
         FileOutputStream  out = new FileOutputStream(fout);
         out.write(data);
         out.close();
         din.close();
         count++;
         return fout;
     }


     // Modifies byte array in place
     public void fuzz(byte[] in, int start, int length) {

         byte[] fuzz = new byte[length];
         random.nextBytes(fuzz);
         System.arraycopy(fuzz, 0, in, start, fuzz.length);

     }

}</pre>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<table cellspacing="0" cellpadding="0" width="40%" align="right" border="0">
				<tbody>
						<tr>
								<td width="10">
										<img height="1" alt="" src="http://www.ibm.com/i/c.gif" width="10" />
								</td>
								<td>
										<table cellspacing="0" cellpadding="5" width="100%" border="1">
												<tbody>
														<tr>
																<td bgcolor="#eeeeee">
																		<a name="N1009E">
																				<b>About the code</b>
																		</a>
																		<br />There are many ways I could optimize the code in <a href="http://www-128.ibm.com/developerworks/java/library/j-fuzztest.html#listing1"><font color="#996699">Listing 1</font></a>. For instance, it's a really good candidate for a memory mapped file with <code>java.nio</code>. I could also improve its error handling and configurability. Because I don't want to let those details get in the way of the ideas I'm presenting here, I've left it as is. </td>
														</tr>
												</tbody>
										</table>
								</td>
						</tr>
				</tbody>
		</table>
		<p>Fuzzing the file is easy. Passing it to the application is normally not much harder. Scripting languages like AppleScript or Perl are often the best choice for writing this part of the fuzz test. For GUI programs, the hardest part can be recognizing whether the application indicated the right failure mode. Sometimes it's simplest to have a human sit in front of the program and mark each test as pass or fail. Be sure to individually name and save all the random test cases generated so you can reproduce any failures you detect with this procedure. </p>
		<p>
				<a name="N100AF">
						<span class="atitle">Defensive coding</span>
				</a>
		</p>
		<p>Solid code follows this fundamental principle: <i>Never accept external data into your program without verifying it for consistency and sanity.</i></p>
		<p>If you read a number from a file and expect it to be positive, check that it is before further processing with that number. If you expect a string to contain only ASCII letters, be sure that it does. If you think a file contains an integral multiple of four bytes, then check that. Never assume that any characteristic of externally-supplied data is as you expect. </p>
		<p>The most common mistake is to assume that because an instance of your program wrote the data out, it can read that data back in again without verifying it. This is dangerous! The data could have been overwritten on disk by another program. It could have been corrupted by a failing disk or a bad network transfer. It could have been modified by another program that had a bug. It could even have been deliberately modified in an effort to subvert your program's security. Assume nothing. Verify everything.</p>
		<p>Of course, error handling and verification is ugly, annoying, inconvenient, and thoroughly despised by programmers the world over. Sixty years into the computer age, we still aren't checking basic things like the success of opening a file or whether memory allocation succeeds. Asking programmers to test each byte and every invariant when reading a file seems hopeless -- but failing to do so leaves your programs vulnerable to fuzz. Fortunately, help is available. Properly used, modern tools and technologies can significantly alleviate the pain of hardening your applications. In particular, three techniques stand out: </p>
		<ul>
				<li>Checksums 
</li>
				<li>Grammar based formats such as XML 
</li>
				<li>Verified code such as Java </li>
		</ul>
		<p>
				<a name="N100CE">
						<span class="smalltitle">
								<strong>
										<font face="Arial">Fuzz proofing with checksums</font>
								</strong>
						</span>
				</a>
		</p>
		<p>The simplest thing you can do to protect against fuzzing is add a checksum to your data. For example, you can sum up all the bytes in the file and then take the remainder when dividing by 256. Store the resulting value in one extra byte at the end of the file. Then, before trusting the input data, verify that the checksum matches. This very simple scheme reduces the risk of undetected accidental failure to about 1 in 256. </p>
		<p>Robust checksum algorithms like MD5 and SHA do much more than simply take the remainder when dividing by 256. In the Java language, the <code>java.security.DigestInputStream</code> and <code>java.security.DigestOutputStream</code> classes provide convenient means for attaching a checksum to your data. Using one of these checksum algorithms reduces the chance of accidental corruption to less than one in a billion (though deliberate attacks are still a possibility, as you'll see). </p>
		<p>
				<a name="N100E1">
						<span class="smalltitle">
								<strong>
										<font face="Arial">XML storage and validation</font>
								</strong>
						</span>
				</a>
		</p>
		<p>Storing your data in XML is an excellent way to avoid problems with data corruption. While XML was originally intended for Web pages, books, poems, articles, and similar documents, it has found broad success in almost every field ranging from financial data to vector graphics to serialized objects.</p>
		<p>
		</p>
		<table cellspacing="0" cellpadding="0" width="40%" align="right" border="0">
				<tbody>
						<tr>
								<td width="10">
										<img height="1" alt="" src="http://www.ibm.com/i/c.gif" width="10" />
								</td>
								<td>
										<table cellspacing="0" cellpadding="5" width="100%" border="1">
												<tbody>
														<tr>
																<td bgcolor="#eeeeee">
																		<a name="N100EB">
																				<b>Impractical boundaries</b>
																		</a>
																		<br />If you really wanted to break an XML parser, there are a few ways you could try to do it. For instance, most XML parsers are subject to certain maximum sizes. SAX parsers will fail if an element name is more than 2.2 billion characters long (the maximum size of a Java <code>String</code>). In practice, however, these limits are so high that you'll run out of memory long before reaching them. </td>
														</tr>
												</tbody>
										</table>
								</td>
						</tr>
				</tbody>
		</table>
		<p>The key characteristic that makes XML formats resistant to fuzz is that an XML parser assumes <i>nothing</i> about the input. This is precisely what you want in a robust file format. XML parsers are designed so that any input (well-formed or not, valid or not) is handled in a defined way. An XML parser can process <i>any</i> byte stream. If your data first passes through an XML parser, all you need to be ready for is whatever the parser can give you. For instance, you don't need to check whether the data contains null characters because an XML parser will never pass you a null. If the XML parser sees a null character in its input, it throws an exception and stops processing. You still need to handle this exception of course, but writing a <code>catch</code> block to handle a detected error is much simpler than writing code to detect all possible errors. </p>
		<p>For further security you can validate your document with a DTD and/or a schema. This checks not only that the XML is well-formed, but that it's at least close to what you expect. Validation will rarely tell you everything you need to know about a document, but it makes it easy to write a lot of simple checks. With XML, it is very straightforward to strictly limit the documents you accept to the formats you know how to handle.</p>
		<p>Still, there will be pieces of the code you can't validate with a DTD or schema. For example, you can't test whether the price of an item in an invoice is the same as the price for that item in your inventory database. When receiving an order document from a customer that contains the price, whether in XML or any other format, you should always check to make sure the customer hasn't modified the price before submitting it. However, you can implement these last checks with custom code. </p>
		<p>
				<a name="N10108">
						<span class="smalltitle">
								<strong>
										<font face="Arial">Grammar-based formats</font>
								</strong>
						</span>
				</a>
		</p>
		<p>One characteristic that makes XML so fuzz-resistant is that the format is carefully and formally defined using a Backus-Naur Form (BNF) grammar. Many parsers are built directly from this grammar using parser-generator tools such as JavaCC or Bison. The nature of such a tool is to read an arbitrary input stream and determine whether or not it satisfies the grammar. </p>
		<p>If XML is not appropriate for your file format, you can still get the robustness of a parser-based solution. You'll have to write your own grammar for the file format, however, and then develop your own parser to read it. Rolling your own is a lot more work than just using an off-the-shelf XML parser. Nonetheless, it is a far more robust solution than simply loading the data into memory without formally verifying it against a grammar. </p>
		<p>
				<a name="N10113">
						<span class="smalltitle">
								<strong>
										<font face="Arial">Java code verification</font>
								</strong>
						</span>
				</a>
		</p>
		<p>Many of the crashes resulting from fuzz testing are direct results of memory allocation mistakes and buffer overflows. Writing your application in a safe, garbage-collected language that executes in a virtual machine such as Java or managed C# eliminates many potential problems. Even if you're writing your code in C or C++, you should use a reliable garbage-collection library. In 2006, no desktop or server programmers should be managing their own memory. </p>
		<p>The Java runtime features an additional layer of protection for its own code. Before a .class file is loaded into the virtual machine, it is verified by a bytecode verifier and optionally a <code>SecurityManager</code>. Java does not assume that the compiler that created the .class file was non-buggy or behaving correctly. The Java language was designed from day one to allow the execution of untrusted, potentially malicious code in a secure sandbox. It doesn't even trust the code it, itself, has compiled. After all, someone could have changed the bytecode manually with a hex editor to attempt to trigger a buffer overflow. We should all have this level of paranoia about input to our programs. </p>
		<p>
				<br />
		</p>
		<table cellspacing="0" cellpadding="0" width="100%" border="0">
				<tbody>
						<tr>
								<td>
										<img height="1" alt="" src="http://www.ibm.com/i/v14/rules/blue_rule.gif" width="100%" />
								</td>
						</tr>
				</tbody>
		</table>
		<table class="no-print" cellspacing="0" cellpadding="0" align="right">
				<tbody>
						<tr align="right">
								<td>
										<table cellspacing="0" cellpadding="0" border="0">
												<tbody>
														<tr>
																<td valign="center">
																		<img height="16" alt="" src="http://www.ibm.com/i/v14/icons/u_bold.gif" width="16" border="0" />
																		<br />
																</td>
																<td valign="top" align="right">
																		<a class="fbox" href="http://www-128.ibm.com/developerworks/java/library/j-fuzztest.html#main">
																				<b>
																						<font color="#996699" size="2">Back to top</font>
																				</b>
																		</a>
																</td>
														</tr>
												</tbody>
										</table>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<br />
		<p>
				<a name="N10122">
						<span class="atitle">Think like the enemy</span>
				</a>
		</p>
		<p>Each of the previous techniques goes a long way toward preventing accidental damage. Taken together and implemented properly, they reduce the chance of undetected, unintentional damage to essentially zero. (Well, not quite zero, but of the same order of magnitude as the chance of a stray cosmic ray causing your CPU to add 1+1 and come up with 3.) But not all data corruption is unintentional. What if someone is deliberately introducing bad data in the hopes of breaching your program's security? Thinking like a cracker is the next step in defending your code.</p>
		<p>Switching back to an attacker's mode of thinking, let's suppose the application you're attacking is written in the Java programming language, uses non-native code, and stores all external data in XML, which is thoroughly validated before acceptance. Can you still attack it successfully? Yes, you can. A naive approach that randomly changes bytes in the file is unlikely to succeed, however. You need a more sophisticated approach that accounts for the program's built-in error-detection mechanisms and routes around them. </p>
		<p>When you're testing a fuzz-resistant application, you can't do pure blackbox testing, but with some obvious modifications, the basic ideas still apply. For example, consider checksums. If a file format contains a checksum, then you simply modify the checksum so it matches your random data before passing the file to the application.</p>
		<p>For XML, try fuzzing individual element content and attribute values rather than selecting a random section of the bytes in the document to replace. Be careful to replace data with legal XML characters rather than random bytes, because even a hundred bytes of random data is almost certain to be malformed. You can change element and attribute names too, as long as you're careful to make sure the resulting document is still well formed. If the XML document is checked against a very restrictive schema, you'll need to figure out what the schema <i>isn't</i> checking to determine where you can productively fuzz.</p>
		<p>A really restrictive schema combined with code-level verification of the remaining data may leave you with no room to maneuver. As a developer, this is what you should strive for. The application should be able to process meaningfully any stream of bytes you send it that it does not reject as <i>de jure</i> invalid. </p>
		<p>
				<br />
		</p>
		<table cellspacing="0" cellpadding="0" width="100%" border="0">
				<tbody>
						<tr>
								<td>
										<img height="1" alt="" src="http://www.ibm.com/i/v14/rules/blue_rule.gif" width="100%" />
								</td>
						</tr>
				</tbody>
		</table>
		<table class="no-print" cellspacing="0" cellpadding="0" align="right">
				<tbody>
						<tr align="right">
								<td>
										<table cellspacing="0" cellpadding="0" border="0">
												<tbody>
														<tr>
																<td valign="center">
																		<img height="16" alt="" src="http://www.ibm.com/i/v14/icons/u_bold.gif" width="16" border="0" />
																		<br />
																</td>
																<td valign="top" align="right">
																		<a class="fbox" href="http://www-128.ibm.com/developerworks/java/library/j-fuzztest.html#main">
																				<b>
																						<font color="#996699" size="2">Back to top</font>
																				</b>
																		</a>
																</td>
														</tr>
												</tbody>
										</table>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<br />
		<p>
				<a name="N1013C">
						<span class="atitle">In conclusion</span>
				</a>
		</p>
		<p>Fuzz testing can demonstrate the presence of bugs in a program. It doesn't prove that no such bugs exist. Nonetheless, passing a fuzz test greatly improves your confidence that an application is robust and secure against unexpected input. If you've fuzzed your program for 24 hours and it's still standing, then it's unlikely that further attacks of the same sort will compromise it. (Not impossible, mind you, just less likely.) If fuzz testing does reveal bugs in your programs, you should fix them. Rather than plugging random bugs as they appear, it may be more productive to fundamentally harden the file format through the judicious use of checksums, XML, garbage collection, and/or grammar-based file formats.</p>
		<p>Fuzz testing is a crucial tool for identifying real errors in programs, and one that all security-aware and robustness-oriented programmers should have in their toolboxes. </p>
		<p>
				<br />
				<br />
		</p>
		<p>
				<a name="resources">
						<span class="atitle">Resources</span>
				</a>
		</p>
		<p>
				<b>Learn</b>
				<br />
		</p>
		<ul>
				<li>
						<a href="http://www.ibm.com/developerworks/views/java/libraryview.jsp?search_by=code+quality:">
								<i>
										<font color="#5c81a7">In pursuit of code quality</font>
								</i>
						</a>: Want more? There's an entire developerWorks series devoted to today's code testing techniques.<br /><br /></li>
				<li>"<a href="http://www.ibm.com/developerworks/java/library/x-javaxmlvalidapi.html"><font color="#5c81a7">The Java XML validation API</font></a>" (Elliotte Rusty Harold, developerWorks, August 2006): Find out what the Java 5 XML validation API can do for you.<br /><br /></li>
				<li>"<a href="http://www.ibm.com/developerworks/rational/library/4929.html"><font color="#5c81a7">Test before you code</font></a>" (Gary Pollice, developerWorks, June 2004): A useful overview of test-first programming concepts and methods.<br /><br /></li>
				<li>"<a href="http://folklore.org/StoryView.py?project=Macintosh&amp;story=Monkey_Lives.txt"><font color="#5c81a7">Macintosh stories: Monkey Lives</font></a>" (Andy Hertzfeld, Folklore): Describes fuzz testing the first Macintosh (though the term had yet to be invented back then).<br /><br /></li>
				<li>"<a href="ftp://ftp.cs.wisc.edu/paradyn/technical_papers/fuzz.pdf"><font color="#5c81a7">An Empirical Study of the Reliability of UNIX Utilities</font></a>" (B.P. Miller, L. Fredriksen, B. So; <i>Communications of the ACM 33</i>, December 1990): First used the word <i>fuzz</i> to describe random data-based testing.<br /><br /></li>
				<li>"<a href="http://www.cs.wisc.edu/~bart/fuzz/fuzz.html"><font color="#5c81a7">Fuzz Testing of Application Reliability</font></a>": The original fuzz testing Web site.<br /><br /></li>
				<li>"<a href="http://www.mulberrytech.com/Extreme/Proceedings/html/2005/Harold01/EML2005Harold01.html"><font color="#5c81a7">Obscuring XML</font></a>" (Elliotte Rusty Harold, Extreme Markup Languages 2005): This paper introduced a tool for randomizing XML data while maintaining well-formedness. The goal then was to aid in bug reporting, but the same techniques could be used to fuzz test XML.<br /><br /></li>
				<li>
						<a href="http://www.cafeaulait.org/books/javaio2/">
								<font color="#5c81a7">
										<i>Java I/O</i>, Chapter 12</font>
						</a> (Elliotte Rusty Harold, O'Reilly, 2006): Discusses the calculation of checksum in Java using the <code>DigestInputStream</code> and <code>DigestOutputStream</code> classes.<br /><br /></li>
				<li>
						<a href="http://en.wikipedia.org/wiki/Fuzz_testing">
								<font color="#5c81a7">Wikipedia: Fuzz testing</font>
						</a>: A customarily excellent entry.<br /><br /></li>
				<li>
						<a href="http://www.ibm.com/developerworks/java/">
								<font color="#996699">The Java technology zone</font>
						</a>: Hundreds of articles about every aspect of Java programming.<br /><br /></li>
				<li>
						<a href="http://www.ibm.com/developerworks/offers/techbriefings/?S_TACT=105AGX11&amp;S_CMP=art">
								<font color="#5c81a7">developerWorks technical events and webcasts</font>
						</a>: Keeping you current.<br /><br /></li>
		</ul>
		<p>
				<br />
				<b>Get products and technologies</b>
				<br />
		</p>
		<ul>
				<li>
						<a href="http://www.infosecinstitute.com/blog/2005/12/fuzzers-ultimate-list.html">
								<font color="#5c81a7">Fuzzers: The ultimate list</font>
						</a>: Various open source fuzz testing tools collected by Jack Koziol.<br /><br /></li>
		</ul>
		<p>
				<br />
				<b>Discuss</b>
				<br />
		</p>
		<ul>
				<li>
						<a href="http://www.ibm.com/developerworks/forums/dw_forum.jsp?forum=812&amp;cat=10">
								<font color="#5c81a7">Improve Your Code Quality</font>
						</a>: Andrew Glover brings his considerable expertise as a consultant focused on improving code quality to this moderated discussion forum.</li>
		</ul>
		<p>
				<br />
				<br />
		</p>
		<p>
				<a name="author">
						<span class="atitle">About the author</span>
				</a>
		</p>
		<p>
		</p>
		<table cellspacing="0" cellpadding="0" width="100%" border="0">
				<tbody>
						<tr>
								<td colspan="3">
										<img height="5" alt="" src="http://www.ibm.com/i/c.gif" width="100%" />
								</td>
						</tr>
						<tr valign="top" align="left">
								<td>
										<p>
												<img height="80" alt="Photo of Elliot Rusty Harold" src="http://www-128.ibm.com/developerworks/i/p-eharold.jpg" width="64" align="left" />
										</p>
								</td>
								<td>
										<img height="5" alt="" src="http://www.ibm.com/i/c.gif" width="4" />
								</td>
								<td width="100%">
										<p>Elliotte Rusty Harold is originally from New Orleans, to which he returns periodically in search of a decent bowl of gumbo. However, he resides in the Prospect Heights neighborhood of Brooklyn with his wife Beth and cats Charm (named after the quark) and Marjorie (named after his mother-in-law). He's an adjunct professor of computer science at Polytechnic University, where he teaches Java and object-oriented programming. His <a href="http://www.cafeaulait.org/"><font color="#5c81a7">Cafe au Lait</font></a> Web site has become one of the most popular independent Java sites on the Internet, and his spin-off site, <a href="http://www.cafeconleche.org/"><font color="#5c81a7">Cafe con Leche</font></a>, has become one of the most popular XML sites. His most recent book is <a href="http://www.cafeaulait.org/books/javaio2/"><font color="#5c81a7">Java I/O, 2nd edition</font></a>. He's currently working on the <a href="http://www.xom.nu/"><font color="#5c81a7">XOM</font></a> API for processing XML, the <a href="http://jaxen.codehaus.org/"><font color="#5c81a7">Jaxen</font></a> XPath engine, and the <a href="http://jester.sourceforge.net/"><font color="#5c81a7">Jester</font></a> test coverage tool.</p>
								</td>
						</tr>
				</tbody>
		</table>
		<br /><img src ="http://www.blogjava.net/mlh123caoer/aggbug/93403.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/mlh123caoer/" target="_blank">草儿</a> 2007-01-12 13:28 <a href="http://www.blogjava.net/mlh123caoer/archive/2007/01/12/93403.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>SCA/SDO走向成熟 将正式成为SOA标准</title><link>http://www.blogjava.net/mlh123caoer/archive/2007/01/12/93334.html</link><dc:creator>草儿</dc:creator><author>草儿</author><pubDate>Fri, 12 Jan 2007 01:39:00 GMT</pubDate><guid>http://www.blogjava.net/mlh123caoer/archive/2007/01/12/93334.html</guid><wfw:comment>http://www.blogjava.net/mlh123caoer/comments/93334.html</wfw:comment><comments>http://www.blogjava.net/mlh123caoer/archive/2007/01/12/93334.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/mlh123caoer/comments/commentRss/93334.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/mlh123caoer/services/trackbacks/93334.html</trackback:ping><description><![CDATA[本系列的主要内容是展望2007年即将出现的面向服务架构的标准情况。本文将首先将介绍服务组件架构(Service component architecture,SCA)和服务数据对象(Service Data Object,SDO)。2007年SCA规范和SDO规范逐渐成熟，在新的一年，SCA规范和SDO规范将正式被归为SOA标准。
<p>查看第二部分：<a href="http://searchwebservices.techtarget.com.cn/comment/464/3033464.shtml" target="_blank"><font face="Verdana" color="#0000ff">WS-Policy今年进入SOA标准审核流程</font></a></p><p>　　SCA规范和SDO规范将成为专门提供编程模型的标准，开发人员可以在创建Web服务时使用SCA和SDO规范，尽管此时SCA规范和SDO规范还没有完全成熟，达到标准水平，但是2007年他们一定能够成为SOA标准。</p><p>　　2006年7月，希望曾到来过，有消息表明SCA规范和SDO规范有望在去年圣诞节时正式成为SOA标准。开放SOA(OSOA)组织，一个由多家提供商包括IBM、 BEA Systems Inc、和Oracle Corp等公司自发成立的组织，目前正在致力于SCA和SDO规范晋升成为SOA标准的工作。去年夏天OSOA组织预测SCA和SDO规范将于2006年底正式成为SOA标准。现在看来，这似乎会是2007年的某一天。</p><p>　　在回复询问关于SCA和SDO规范更新情况的电子邮件中，IBM 的SOA合作伙伴、项目经理、规范编写人之一Graham J Barber这样答到：“我们希望在2007年第一季度将SCA规范的主要部分作为第一版推出。之后，我们希望将两个规范与已发布的V2.1 SDO规范放到一起，申请成为SOA标准。”</p><p>　　不论SCA规范是否已经完善或是否能成为SOA标准，SCA都是已被广大提供商应用于产品的SOA技术。甲骨文工具与中间件副总裁兼首席架构师Ted Farrell说，SCA规范是一种实用的技术。目前甲骨文的WebCenter Suite 就使用了SCA规范，使开发人员方便开发SOA和Web 2.0项目，他说。</p><p>　　Rogue Wave Software，Quovadx, Inc.的一家分公司，本月初宣布开始使用SDO规范，并将SDO加入产品名称，公司的SOA工具套装将被称为HydraSDO。</p><p>　　甲骨文的Farrell说，正式发布SOA标准是一件好事，他希望正式标准尽早出台，不过他真正关心的是在工具和应用程序开发中如何有效地使用SCA/SDO技术。</p><p>　　“我们对SCA何时成为标准十分感兴趣，现在我们叫它SCA伪标准，”他说。“我们不希望有所有权问题，因为采用开放结构会有许多好处。”</p><p>　　但是Farrell说，最重要的是，一个标准需要适用于应用程序，并有广泛的行业支持。</p><p>　　“SCA规范更趋于点对点模式，”他说。“IBM和BEA在推广一些标准的时候受到一些挫折，所以他们开始成立开放SOA组织。甲骨文以及其他一些提供商加入了该组织。尽管它不是以前的标准组织，但是它在不断发展，不断进步，其实我们最为企业软件提供商真的希望把这些规范变为一种软件标准，希望能够为SOA的发展献出一份力量。”</p><p>　　Farrell说SCA/SDO规范似乎在走业务处理执行语言(BPEL)的发展道路。业务处理执行语言(BPEL)最初由IBM和微软共同努力开发出第一个版本，之后BEA、 SAP AG和 Siebel Systems先后使用BPEL，现在甲骨文也开始使用BPEL。2003年，这些提供商正式将BPEL提交给开放标准组织OASIS标准化，2003年4月6日，OASIS组织用WS-BPEL的名字吸纳了BPEL标准。2003年5月3日，SAP/SIEBEL加入并共同推出WS-BPEL1.1版。2003年5月16日， WS-BPEL2.0的草案也在当时被纳入议事日程。</p><p>　　SOA项目的开发人员和架构师应该从现在开始就接触这些规范，不应该等着它们成熟成为正式标准，Harte-Hanks (HHS) 公司Aberdeen Group 企业集成副总裁Peter S. Kastner说。他认为SOA的工作人员都应该熟悉这些规范，并促进它们的发展。</p><p>　　“在未来几年，将迅速推出一批与SOA相关的标准，所以对用户来说，最好简要地使用这些标准，从某种意义上说，这是可能的，”他说。“基本上，变化是不可避免的，所以勇于面对变化，适应变化。如果要等到所有标准都完善，之后出台，我像那你会疯掉，这大概需要十年的时间。”</p><img src ="http://www.blogjava.net/mlh123caoer/aggbug/93334.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/mlh123caoer/" target="_blank">草儿</a> 2007-01-12 09:39 <a href="http://www.blogjava.net/mlh123caoer/archive/2007/01/12/93334.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>程序员眼中的2007:寻找软件开发利器</title><link>http://www.blogjava.net/mlh123caoer/archive/2007/01/12/93333.html</link><dc:creator>草儿</dc:creator><author>草儿</author><pubDate>Fri, 12 Jan 2007 01:38:00 GMT</pubDate><guid>http://www.blogjava.net/mlh123caoer/archive/2007/01/12/93333.html</guid><wfw:comment>http://www.blogjava.net/mlh123caoer/comments/93333.html</wfw:comment><comments>http://www.blogjava.net/mlh123caoer/archive/2007/01/12/93333.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/mlh123caoer/comments/commentRss/93333.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/mlh123caoer/services/trackbacks/93333.html</trackback:ping><description><![CDATA[软件开发生命周期包括需求分析、设计、开发、测试、交付部署等各个阶段，以及贯穿在整个开发过程的软件开发项目管理环节，2006年，在每一个阶段都出现了令人眼花缭乱的技术与应用，同时这些技术还将进一步影响2007年的发展，令人充满期待。
<p>　　<strong>建模和开发工具平台</strong></p><p>　　UML在版本升级到2.0以后，原来的UML工具的大哥大Rational从风行到被收购，现在几乎没有了声音。</p><p>　　建模工具没有太显著的变化，倒是开发工具出现了从原来的百花齐放到现在只有少数巨头竞争的局面。其中最耀眼的当属诞生于IBM，后在开源社区得到快速发展的Eclipse,目前它已进入嵌入式开发领域。另一个就是微软携其强大财力与人力打造的VSTS开发工具平台，它将成为可以贯穿整个软件开发生命周期和扮演不同的角色的平台，在最近也有不俗表现。此外还有Sun的NetBean IDE开发工具和BEA的WorkShop开发工具等。</p><p>　　这些开发工具平台都可以进入整个软件开发生命周期，并且可以在其上进行各种不同应用的开发，说白了就是兼容性足够强。</p><p>　　<strong>开发与应用</strong></p><p>　　不论使用何种工具，真正最活跃的仍然是应用与开发。JavaEE5的发布，EJB3.0标准的落地，标注取代部署描述符，实体即是POJO等，也许这些改变对Java进行轻量级应用开发的复杂性会有所改变。在软件开发界最流行的框架，包括Struts、Spring、Hibernate等，这些分布在Web容器和EJB容器中的各种应用框架变得让人眼花缭乱，要选择最适合自己的看来越来越困难了。由于JavaEE5的发布，著名的JBoss应用服务器的结构也发生了较大的变化。微软.NET的2.0平台和下一代操作系统Window Vista桌面版发布，同时提供给广大用户的WinFX平台，不仅给开发者而且给用户带来了挑战。</p><p>　　由Ruby和Retail的联姻，AJAX的新瓶装旧洒，再加上Web2.0应用概念上的炒作，脚本语言、Web开发与应用在今年着时火了一把，因此今年搭上顺风车的PHP也要求能够同Java应用交互，克服语言与平台的障碍。</p><p>　　桌面与企业服务器的开发应用也有相当发展，中间件市场、数据库、ERP等各种应用随着SOA得到市场的认可，各种技术与应用以及SOA的产品也逐渐多了起来。随着3G时代的到来，智能手机占有率的提升，手机平台的开发市场正进一步;不仅是手机，数字电视、各种电器和消费类电子产品的智能化发展也促使嵌入式领域的开发发生了很大变化，如：IP机顶盒、基于GPS全球定位系统的设备、工业自动化和医疗设备等，商业平台与开源Liunx平台共存。</p><p>　　<strong>开源、互联网及其他</strong></p><p>　　开源软件逐渐挺进企业主流应用，不仅是Linux，还有Boss中间件、Mysql数据库、EnterpriseDB数据库等，而且还有各种应用软件，包括：Open office办公套件、Firefox浏览器、ERP、CRM等等。开源力量的加入也使得非常多的应用进入到微软平台上，在微软的.Net平台上也出现了大量的开源应用软件。</p><p>　　互联网最大的应用与技术就是搜索、软件服务化(Software as a Service)。不管是通用搜索还是行业垂直搜索，不管是互联网搜索还是企业搜索，都已经不仅针对文本而且开始向音视频搜索发展了。</p><p>　　最后不要忘了，由于人们对应用要求的提高，测试在这几年显得越来越重要了，测试工具与测试理论都有很大发展，这一点也值得关注。</p><div id="textpage"><li>第1页：<a href="http://searchwebservices.techtarget.com.cn/comment/183/3034183.shtml" target="_self"><span><font color="#333366">寻找软件开发利器</font></span></a></li><li>第2页：<a href="http://searchwebservices.techtarget.com.cn/comment/183/3034183_1.shtml" target="_self"><font color="#333366">手机软件开发将与PC趋同</font></a></li><li>第3页：<a href="http://searchwebservices.techtarget.com.cn/comment/183/3034183_2.shtml" target="_self"><font color="#333366">注重测试需求 做好流程建设</font></a></li><li>第4页：<a href="http://searchwebservices.techtarget.com.cn/comment/183/3034183_3.shtml" target="_self"><font color="#333366">网络安全软件开发趋势</font></a></li><li>第5页：<a href="http://searchwebservices.techtarget.com.cn/comment/183/3034183_4.shtml" target="_self"><font color="#333366">降低开发复杂性</font></a></li><li>第6页：<a href="http://searchwebservices.techtarget.com.cn/comment/183/3034183_5.shtml" target="_self"><font color="#333366">工作流: 国内国际两极分化</font></a></li><li>第7页：<a href="http://searchwebservices.techtarget.com.cn/comment/183/3034183_6.shtml" target="_self"><font color="#333366">Java走上开源之路</font></a></li></div><p><strong>手机软件开发将与PC趋同</strong></p><p>　　<em>王权平</em></p><p><em>　　资深程序员，供职于威盛电子(中国)有限公司，从事GSM/GPRS芯片组的开发，主要工作包括协议软件设计、开发与测试，以及智能手机平台通信中间件的设计与开发。</em></p><p>　　2006年出现了很多叫好也叫座的手机产品，这些成功手机的背后，都明显地揭示出了手机软件开发技术的若干发展趋势。2007年手机软件技术将继续迅速发展，无论单处理器平台或是双处理器平台，网络应用和多媒体应用都将是主要的开发方向，而C++和Java将是首选的开发语言。</p><p>　　未来，传统的单处理器手机平台仍将在低价手机和特色手机市场上保持不可替代的优势。其软件通常都由芯片厂商和手机设计公司来提供，除了J2ME平台外，缺乏开放和标准的API是其固有的缺陷。因此几乎没有来自第三方的原生的面向其处理器和编译平台优化的软件，用户自行扩展的能力较差。展望未来，除了集成更多的应用软件(如电子邮件、电子书和多媒体播放程序等)外，单处理器平台上的软件开发工作主要集中在新硬件模块的驱动程序以及图形用户界面的创新和提高上。就开发语言而言，C和C++仍然是首选;在底层通信软件尤其是协议栈的实现上，C语言仍将继续居统治地位;当然在驱动程序中，汇编语言也是不可或缺的。单处理器平台上第三方开发人员的开发空间在于J2ME平台，但是各个解决方案对Java语言支撑能力的差异，使得Java程序很难达到真正的与平台无关。不过，随着硬件能力的与提高和Java虚拟机的改善，特别是硬件级Java加速和ARM平台Java优化指令等特性的引入，可以预料J2ME将会成为单处理解决方案的基础软件平台。</p><p>　　双处理器平台由运行通信协议的基带处理器和运行用户界面程序的应用处理器组成，是智能手机的基础平台。未来智能手机平台的软件开发中，中间件和应用程序都有很大的发展空间和需求。中间件主要包括图形库和通信库两部分。图形库重点在于提供更加华丽和友善的用户界面，增强用户的操作体验，据称WinCE6.0即将提供Vista风格的界面;3D加速将是继2D加速后的第二个亮点;另外，图形库也将重点支持硬件级的多媒体加速技术，从而支持包括移动音频和视频，特别是手机电视的应用。通信库部分将重点在统一的框架内整合各种广域、局域乃至个域通信技术。应用程序部分，网络应用将会是2007年的发展重点。就开发技术而言，J2ME在智能手机上的性能优于单处理平台，因此笔者看好基于J2ME平台的手机游戏和网络应用;而基于C++的网络编程和多媒体编程仍将继续是Symbian平台、WinCE平台，以及Linux上Qt平台的的主要开发领域;另外PC平台上的基础软件组件，如数据库技术等，将逐渐移植到手机平台上，提供其嵌入式的版本，以适应手机平台的硬件和软件限制。但是由于三大平台存在的巨大差异，软件的可移植性将成为一个重要的问题。</p><p>　　<strong>核心观点</strong></p><p>　　随着中间件的加强，手机应用软件开发将逐渐与PC趋同，将出现大量的个人软件开发者和第三方软件开发商，手机软件产业势必会有很大的发展。<br /><strong>注重测试需求 做好流程建设</strong></p><p>　　<em>戴金龙</em></p><p><em>　　注册PMP,GB/GJB/ISO/CMMI内审员。原嫦娥工程地面应用系统质量组专家。历任某外企测试技术经理、项目经理及运营经理。对当代软件测试理论及工程实践有较好的领悟。</em></p><p>　　当前，测试作为一项职业吸引了越来越多的优秀人才;测试作为控制软件质量的有效手段，融入到了越来越多企业高层的管理理念中;测试作为一门学科，获得了前所未有的壮大。但在测试技术蓬勃发展的另一方面，测试行业也在迅速地积累着各种问题，在接下来的一年里某些隐藏的问题可能会表现得很显著。</p><p>　　第一个问题是如何让测试更有效地锲入到不规范的软件开发过程中。提出这个问题恐怕会有不少人大吃一惊：这类企业为什么不先规范软件的开发过程呢?这是不是一个伪问题?其实，目前有不少软件企业都处在这种状态。但这些企业的管理层并不承认自己的开发过程不规范，反而认为这是一种灵活的、有个人特色的高效管理。这样的氛围造成软件质量低下自是意料中的事情。</p><p>　　即使企业管理层了解到测试是解决质量问题的有效途径，实施软件测试也是需要代价的。目前的测试学科所提供的技术、流程、管理及方法论都是假设是在良好的(至少规范的)开发过程、管理氛围及测试环境中实施的，并没有提供在不规范软件开发过程中做测试的解决方案，这样就出现了所谓“理论”与“实践”的偏差。解决的办法有两个:一种是变革企业文化，规范开发过程，建立测试所需的相关环境，从而实施规范、严格、有序的软件测试;另一种就是拓展测试理论，针对不规范开发过程的特点，找到弥补、折衷的解决办法。根据笔者对国内软件企业的了解，后者将是今后一段时间国内软件企业关注的热点话题。</p><p>　　第二个问题是如何清晰地定义软件测试需求，使测试工作目标明确、有的放矢。这个问题是以前的测试学科没有回答清楚的，非常需要深入研究，它将会是今后若干年的研究热点。可能有读者会感到费解：测试需求不就是软件需求吗?其实不然。软件需求用于指导后续设计的展开。而测试需求则是直接源自于客户的质量要求。测试需求的源头非常繁杂，如何删繁就简，拿捏得当，目前没有现成的方法，仍需要做大量理论研究和实践探索。</p><p>　　第三个问题是如何规范软件测试流程以持续提高测试团队的绩效。这个问题目前已有一些答案。如“制定测试计划-设计测试-执行测试-测试分析与总结”等等。从执行的角度而言，这类粗略的阶段划分或许已经够用，没有进一步研究的必要。但对于控制测试过程而言，对于测试服务型企业通过CMMI认证而言，尤其是对于改进软件测试过程而言，几乎是没有帮助的。</p><p>　　<strong>核心观点</strong></p><p>　　在测试技术蓬勃发展的另一方面，测试行业也在迅速地积累着各种问题。<br /><strong>网络安全软件开发趋势</strong></p><p>　　<em>李洋</em></p><p><em>　　中国科学院计算技术研究所博士，资深程序员。从事计算机网络信息安全领域的研发工作，曾参与“国家自然科学基金”、“国家863重大专项”、“国家242信息安全计划”、“国家973计划”等多项国家重点项目、信息安全系统和企业信息系统的研发工作。</em></p><p>　　从当前国际上安全产品的研发情况来看，以防火墙和IDS为主导，以密码技术为基础的产品已经取得了飞速的发展，并在实际应用中发挥了很大的效应，使得网络安全产品的研究及应用工作不断向前推进。2007年，对于网络安全软件开发人员来说，如下几项新的技术值得大家期待：</p><p>　　1.基于开源软件的开发技术</p><p>　　以Linux为代表的开源软件及其开发模式已经深入人心。网络安全软件中最为著名的就是轻量级的入侵检测系统Snort，它已成为众多安全厂商和科研院校研发的重要参照物。纵观网络安全软件的发展趋势，以优秀的开源软件为基础进行研发已成为网络安全界的首选技术途径。</p><p>　　2.嵌入式安全开发技术</p><p>　　随着移动计算和无线网络的普及，以及普适计算概念的提出和应用，移动、无线和无处不在的计算已成为新世纪IT的绝对热点。这些需求都要求在上述条件下进行信息处理和计算，因而以J2ME为代表的嵌入式开发技术也成为很大看点。</p><p>　　尤为值得关注的是，人们在获得上述便利的同时，也在经受着自己的隐密数据随时有可能被窃取和破坏的威胁。那么，如何在当前的嵌入式技术当中综合采用密码理论、PKI基础架构以及其他信息安全技术来提高嵌入式系统的安全性，为未来轻量级的嵌入式计算保驾护航，也必将成为网络安全工作者和软件开发人员关注的一个热点问题。</p><p>　　3.高性能计算服务开发技术</p><p>　　网络带宽的日益增长和单机处理能力已经极不对称。诸如早期的防火墙、IDS等都已经不能满足现实的需求。</p><p>　　因此，采用并行处理技术以及研究和开发高性能网络协议处理技术来缓解上述问题带来的压力是不错的选择。并且，随着64位计算的到来，如何在该硬件平台上进行并行开发、编译等，都是网络安全软件研发人员期待和需要解决的问题。值得期待的是，当今的UTM(统一威胁管理)技术试图在上述各方面取得突破，建立一套高性能、高可靠、完善的网络威胁防范机制，我们拭目以待。</p><p>　　4.可信编程技术</p><p>　　对于安全要求较高的场合，可信计算平台能够为用户提供更加有效的安全防护。而据统计，在网络安全领域，80%以上的网络威胁和漏洞来源于系统自身的Bug，而这些Bug则来源于设计思路以及程序实现。那么，在积极防御外来攻击的同时，提高网络安全软件研发人员自身编程的可靠性，软件开发平台在软件编程中可能出现漏洞(比如最常见的缓冲区溢出等)的地方进行提醒和标注，就可以极大地减少程序实现的硬伤。我们不妨借用可信计算的名号称其为可信编程技术，相信也将是软件研发人员关心的技术，不但可以提高软件可靠性，更能避免用于查找大量重复出现的系统Bug所需的人力和物力。</p><p>　　<strong>核心观点</strong></p><p>　　基于开源软件的开发技术、嵌入式安全开发技术、高性能计算服务开发技术、可信编程技术将是未来网络安全软件开发的四大趋势。<br /><strong>降低开发复杂性</strong></p><p>　　<em>程勇</em></p><p><em>　　Java开放源码软件咨询顾问，Huihoo.org开源软件社区共同创始人，北京中流科技有限公司CTO。</em></p><p>　　Java技术的发展已经走过11个年头，在企业级应用开发领域占领主导地位的JavaEE技术也伴随着Java自身的演变，在2006年发生了许多新的变迁。 随着系统开发复杂度的上升，需要一种更好的解决方案来分解系统的复杂，并简化应用开发的过程。基于众多的因素，选择企业应用开发的架构平台时都需要考虑很多约束，它必须最小化对应用开发本身的影响。因此，一个好的技术平台和应用框架应该具备如下特性：提供应用开发的一致性;提供高端和低端特性;提供管理逐步增长的应用系统的具体方法;为高级开发人员提供指导;能够使不同框架的特性和优点集成到一起进行工作;能够快速进行应用开发，保证产品按市场的需求发布;能够降低项目开发的风险，提升企业的投资回报。</p><p>　　由此，我们不难发现，现在大量涌现的新技术体系和框架，都是在朝着简化应用开发的方向而努力，这些技术包括：</p><p>　　● AJAX AJAX并非一种编程语言，它是使用XHTML或HTML，JavaScript以及XML来建立互动网络应用程序的一种模式。</p><p>　　● 脚本语言 Ruby的发展，使得在Java 语言中使用动态机制成为可能，使用Ruby的动态机制，用户能够改变脚本类的定义。这些Ruby对象允许直接使用方法管理它的状态和行为。</p><p>　　● 应用框架 以Spring为代表JavaEE应用框架是在JavaEE技术体系之上快速构建应用的支撑平台，应用框架通过整合的技术架构，将众多的优秀开源框架融合在一起，为应用开发提供了一个完整的技术解决方案。</p><p>　　● JavaEE 5.0 JavaEE 5.0 是新一代的Java EE技术规范，其中包括JSF、EJB 3.0等十多项全新的技术体系。它的多项新特性为JavaEE应用开发带来了更多的便利。</p><p>　　<strong>核心观点</strong></p><p>　　选择企业应用开发的架构平台时都需要考虑很多约束，它必须最小化对应用开发本身的影响。<br /><strong>工作流: 国内国际两极分化</strong></p><p>　　<em>胡长城</em></p><p><em>　　网名“银狐999”，就职于TIBCO。国内J2EE开源应用的支持者，有过6年的J2EE应用和产品开发及架构经验，是huihoo开源组织的成员。</em></p><p>　　与众多新技术相比，工作流的知名度也许会小一些，但工作流也一直处于不断创新之中。所不同的是，在这个领域新技术的应用是被隐藏在应用理念和架构体系之下的。对于工作流的发展趋势，这里分开两条线来阐述。</p><p>　　第一条线就是单纯从工作流技术应用的发展趋势来探索。在这方面国际上应用水平已经远超越国内，这就是这两年的龙卷风—— BPM(Business Process Management)。很多国际化的大企业已经把BPM定位于一种解决方案。在这一整套解决方案中，工作流技术已经成为流程的服务，围绕这个服务，有各种模块和应用相辅助。BPM解决方案俨然成为一种参考架构: 一方面是以SOA为主导的技术架构，另一方面则包含了一整套的服务。</p><p>　　实际上，BPM的发展是很多年的流程和工作流发展的必然结果。在这个领域的供应商有的由早期的工作流厂商发展而来，如Staffware公司(现已经被Tibco收购); 有的由早期的EAI提供商发展而来，如Tibco; 有的由应用服务器提供商发展而来，如BEA等。在它们的BPM蓝图中有很多相似之处，比如以BPEL规范阐述Business Process。</p><p>　　第二条线从国内工作流应用和技术趋势来分析。这两年已经有部分国内企业采用EAI或BPM技术进行系统整合方面的应用，但大规模地采用BPM解决方案还是很少，不过这是一个趋势。国内目前工作流技术的应用还主要以“办公或业务流程的人工信息化处理”为主，毕竟国内企业和政府的一个很大特征是“以人为主”，而不是“以制度化为主”。在一些集团性的企业和跨省市集中管理性的系统中，分布式流程应用逐渐显现出来。而伴随着国内几年来工作流市场的积淀，早期的一些工作流厂商在寻求“流程分析和监控”方面的突破，而这方面的客户需求也日渐多起来。但短时间内，很难由国内工作流厂商自己取得一些突破，发展起BPM产品。</p><p>　　上述这两条发展线也代表了两极分化。但第一条战线的BPM 解决方案肯定是未来大规模应用的趋势，虽然短时间内对国内工作流应用市场冲击很小，但是政府和国内软件厂商却不应该小觑这个发展趋势。</p><p>　　<strong>核心观点</strong></p><p>　　国际大厂商对工作流的研究重点是把它作为BPM的一部分，为流程服务，而国内还主要以“办公或业务流程的人工信息化处理”为主，短时间内，国内还很难有所突破，推出自己的BPM产品。<br /><strong>Java走上开源之路</strong></p><p>　　<em>孟冬冬</em></p><p><em>　　中科软科技股份有限公司金融保险部系统分析师、软件架构师。9年软件设计开发和6年项目管理经验,精通基于J2EE架构的企业应用系统开发技术。先后在普天、中软等多家软件公司任系统分析员、软件架构师及项目经理。</em></p><p>　　2006年11月13日，Sun公司宣布将Java转为开源。预计到2007年3月份，除了一部分所有权不属于Sun的源代码之外，几乎全部Java技术的源代码都将按照GNU GPL自由软件许可授权协议公开。Java在和.net经历了两年的竞争后已显疲态，相比5岁的.net以及新生的动态语言Ruby，11岁的Java已略显复杂臃肿，甚至在网上还有“Java将死”的论调。Sun选择在此时将Java开源，不管是否是Sun迫不得已、在日薄西山前的最后博弈，但影响之深远却绝对不可小视。它引发的“蝴蝶效应”无疑会使Java技术的生命力更强，走得更远，更可赢得在开发语言竞争中起决定作用的更多程序员的芳心，相信未来Java领域将出现更多令人惊奇的开源产品。</p><p>　　另外Sun还赶在圣诞节前发布了JDK的6.0 Release版本。对JDK而言，“成败皆在应用服务器厂商”。市场占用率最大的应用服务器Weblogic8、WebSphere5成就了1.4，但也限制了JDK5的普及。在JDK5还没有用热时，JDK6就来了。不过，这倒也是好事，可以直接跳过JDK 5去研究JDK6的应用了。</p><p>　　JDK6对笔者的最大吸引力是它在JVM性能上的提升和对XML和Web服务的支持。性能方面，无论是运行时分析功能还是用户对性能情况的反馈，尤其是在Swing方面，JDK6对JIT都有了卓有成效的提升。</p><p>　　一直以来，相对于微软的.net，Java对Web Services的支持复杂得难以接受，也因此产生了优秀的Axis和XFire框架。而在JDK6下，Java程序员也能享受到这种待遇了，不用针对Web服务另外加入额外的工具，不使用任何框架也能写出Web Services程序了。JDK6中固化了XML、Web Services的标准，如StAX、JAXB2、JSR181等。JDK 6在语法方面没有太大改变，最明显的就是添加了对脚本语言的支持，如JavaScript、Ruby、PHP。JDK6 中实现了JSR 223，提供了让脚本语言来访问Java 内部的方法。它可以在运行的时候找到脚本引擎，然后调用这个引擎去执行脚本，这个脚本API 允许程序员为脚本语言提供Java 支持。</p><p>　　另外在JDK6中内置实现了JDBC4支持的Derby数据库，为测试和小型系统的发布提供了便利条件。最后，JDK 6 中对内存泄漏增强了分析以及诊断能力，当遇到Java.lang.OutOfMemory 异常的时候，可以得到一个完整的堆栈信息，并且当堆已满时，会产生一个日志文件来记录这个致命错误。</p><p>　　如果说谈到JDK 6更多的是对未来的一种希望的话，Java full-stack(Java full-stack，意指集成了全部所需功能的Java快速开发框架)则是一种已经可以见到的东西。</p><p>　　很长时间以来，作为一个Java程序员，幸福的是从表现层到持久层都有众多的框架可供选择，痛苦的是在这些框架中挑选出适合自己的框架，而且还要付出将不同层次的框架粘合在一起的设计成本和时间，而架构的稳定性和实用性则往往取决于架构师的设计理念和经验。Ruby on Rails的流行再一次证明了在软件开发领域“简约至上”的真理，它使得诸多Java开发人员把目光放到了“提供最方便好用的Java full-stack框架”上面，因此Java开源社区如雨后春笋般地出现了一批又一批的full-stack框架，如Appfuse、SpringSide、JBoss　Seam、RIFE、Grails、Trails、Rife等。Java领域也从此开始走向full-stack的快速开发道路。笔者就非常喜欢国外的JBoss Seam和国内的SpringSide。</p><p>　　<strong>核心观点</strong></p><p>　　Sun选择在2006年岁末将Java开源，不管是不是Sun的最后博弈，其影响绝对不可估量。从此以后，全世界所有的开发人员都可以对Java源代码进行修改、优化、除错，同时Java也将变为一种真正免费的技术。<br /><strong>网络技术融入软件平台</strong></p><p>　　<em>智雨青</em></p><p><em>　　北京理工大学计算机硕士，8年的电信行业软件开发经历，曾在亿阳信通、北京朗新科技公司供职，中国联通第一版CRM的主要设计与开发者，参与联通多个省级OSS/BSS系统的研发与实施。</em></p><p>　　2006年年初有专家曾经说过，今年软件发展技术很有可能进入到一个无热点时代。的确，我们非常熟悉的网络应用技术、搜索技术、应用行业软件技术等等，已经发展到一个非常成熟的阶段，每一次升级能带给我们的惊喜越来越少。不过，2006年虽没大的“翻天覆地”，却仍涌现出了不少亮点，而这些亮点极有可能会决定今后两三年的应用潮流。</p><p>　　1. Web2.0</p><p>　　Web2.0是2003年之后互联网的热门概念之一。Web2.0技术主要包括: 博客、RSS、百科全书(Wiki)、网摘 、社会网络(SNS)、P2P、即时信息(IM)等。由于这些技术有不同程度的网络营销价值，因此Web2.0在网络营销中的应用已经成为热门领域。尽管对于究竟什么是Web 2.0还有很多的讨论，但有一点可以肯定，Web2.0是以人为核心线索的网。提供更方便用户“织网”的工具，鼓励提供内容;根据用户在互联网上留下的痕迹，组织浏览的线索，提供相关的服务，给用户创造新的价值，给整个互联网带来新的价值，才是Web2.0商业之道。</p><p>　　2. 嵌入式移动开发技术</p><p>　　嵌入式开发技术的发展推动了嵌入式操作系统跨越式发展，也成为现代及未来移动技术发展的重要保障，以微软Windows CE系列、PalmSource公司PalmOS、Nokia公司Symbian等为代表的嵌入式操作系统已在各种移动设备上大量应用。尤为值得一提的是作为行业领先者的微软2006年5月发布了Windows CE 6，凭借重新设计的操作系统(OS)内核架构以及增强的并发处理能力和新集成的工具集，提供了一个更加集成化的嵌入式开发环境，允许开发者将大量更为复杂的应用集成到比以往更加智能的设备中，从而提供高性能的多媒体、Web服务和无线网络连接应用。</p><p>　　3. 中间件技术</p><p>　　随着Internet的快速发展，中间件的定义正在走出其狭义空间，逐步形成更为广义的内涵。其发展主要呈现出两方面的技术趋势: 一方面，支撑软件越来越多地向运行层渗透，提供更强的对系统实现的支持;另一方面，中间件也开始考虑对高层设计和运行部署等开发工作的支持。而这两个技术趋势从本质上说正是源于软件体系结构和软件构件等技术的发展和应用。从广义的角度看，中间件代表了处于系统软件和应用软件之间的中间层次的软件，其主要目的是对应用软件的开发和运行提供更为直接和高效的支撑。中间件技术已成为软件技术的研究热点。</p><p>　　4. 即时通信技术</p><p>　　现在即时通信市场不再只有一种声音，腾讯、微软、IBM、Avaya、Skype、中国移动纷纷将触角伸向了这块市场，诱惑这些大佬们的是即时通信市场的爆发式增长和随之而来的丰厚利润。而移动即时通信作为一项数据业务更是被视为未来3G时代的一大“金矿”。待3G牌照发放，捆绑于移动即时通信之上的包括彩信、彩铃、图片、博客、手机电视等应用都会得到充分发掘。</p><p>　　5. 下一代搜索技术</p><p>　　搜索引擎发展到今天已经增添了很多新的特征，其特色主要体现在“概念集群”和“动态分类”，它通过分析网页之间的关联，建立一种类似人的思维的更智能化的概念分类方式，通过模仿人的思维模式，对要查找的概念进行关键字联想和分类。除了概念集群和动态分类，新一代搜索引擎还更多地体现在个性化方面，这在以前的搜索里是很难做到的。概念集群又分为大众化概念集群和个性化概念集群，通过搜索记录，下一代搜索技术能够帮助每个人建立自己个性化的搜索功能，而且信息是可以分享的。</p><p>　　<strong>核心观点</strong></p><p>　　基于新一代网络技术的各种应用的融合是大势所趋，网络新技术与软件新技术的相互促进将为人类创造一个更为灿烂的IT世界。<br /><strong>互联网将更社区化</strong></p><p>　　<em>康威</em></p><p><em>　　新华社高级工程师，Lotus技术专家。曾任后勤指挥学院教员，获全军科技进步二等奖一次、三等奖四次，2002年7月转业到新华社技术局，是新华社多媒体数据库系统核心成员。</em></p><p>　　互联网的飞速发展成就了搜索引擎今天的地位，同时也推动了网络视频的发展，而Web 2.0又推动了全民的参与性、主动性和互动性，密切了人与人之间的联系，由此形成了线上与线下互动的各种模式，反过来又推动了互联网的壮大。</p><p>　　1. 互联网搜索</p><p>　　2006年的中国互联网搜索依然是百度、Google双头垄断，百度的势头略有提升，垂直搜索成为耀眼的明星，移动搜索也有了一定的发展。未来搜索引擎将会更精准化、智能化、人性化、垂直化和社区化，会以更快的速度为计算机和其他智能终端用户服务。</p><p>　　笔者认为，2007年的中国搜索市场将是一个分水岭，其竞争将达到前所从未有的规模，雅虎、搜狐磨刀霍霍，微软卧薪尝胆，不过双头垄断局面不会改变，走向国际化的百度依然会是龙头老大，而能满足大家特定需求、具有差异化特征的垂直搜索和生活搜索是未来的市场增长点，其搜索商业模式也会更加丰富。2007年，搜索行业的发展必将进一步促进互联网商业模式的创新以及相关技术的提高，成为互联网发展的重要支柱。</p><p>　　2. P2P流媒体</p><p>　　P2P流媒体行业一直都被认为是下一个可能产生井喷效应的互联网领域。P2P体现了真正的“互联网精神”——我为人人，人人为我，但市场是理智而残酷的，在短暂的狂欢过后，P2P流媒体行业所面临的问题与挑战也逐步显露，商业模式不清晰、盗版泛滥、国家政策不明朗等问题不得不令人深思。</p><p>　　网络视频是中国未来几年的热点，目前只有两个方向可以赚大钱: 流媒体巨头与内容大鳄的联姻和微视频，依靠盗版的视频直播与共享只可能是小富即安。只有少数几家有资金、有技术、有影响的流媒体厂商(包括门户网站)才能获得内容大鳄的青睐，留给众多中小型流媒体厂商的只能是微视频。</p><p>　　微视频是指短则30秒，长则不超过20分钟，内容广泛，视频形态多样，涵盖小电影、纪录短片、DV短片、视频剪辑、广告片段等，可通过PC、手机、DV、DC、MP4等多种视频终端摄录或播放的视频短片的统称。短、快、精、大众参与性、随时随地是微视频的最大特点。微视频规避了版权的威胁，降低了带宽的成本，易形成社区，具有一定的赢利模式，随着网络融合的加快，3G和宽带的发展，只要走专业化、特色化、差异化道路，一定大有“钱”途。</p><p>　　3. 互联网社区化</p><p>　　互联网社区化有三种形式: 情感的归属与宣泄，人们可以不受空间限制地自由沟通、发表见解、结交朋友、宣泄情感; 线上与线下的互动，互联网使得人们能够以最快捷的方式广结交天下朋友，很多社区型网站都定期举行各种线下活动; 智慧和经验的共享，充分体现了P2P精神，人们信息需求的满足，需要越来越多地依靠其他用户的力量来满足，社区化的搜索是最好的例子。</p><p>　　社区化的搜索能更好地满足用户的需求，也可以更好地发挥用户的价值。首先他们会享受其他用户贡献的智慧，同时他们在自己使用的过程中几乎不会察觉到在给整个互联网做出贡献。2006年7月13日正式推出以“搜索+博客”为理念的产品——百度空间，这是百度继贴吧、知道、百科后推出的第四个社区类产品，具备个人空间、个人门户等基本特征。这一产品的推出，不仅进一步深化了百度的社区化搜索服务，并凭借其在中国互联网的巨大影响力，进一步推动了中国互联网社区化发展的进程。</p><p>　　<strong>核心观点</strong></p><p>　　未来的互联网将更能体现P2P精神，将更视频化和社区化(当然文字仍会像传统报纸一样不可替代)，同时，在互联网的进化过程中，搜索技术将会改变人们的生活习惯。<br /><strong>应用推动软件技术创新</strong></p><p>　　<em>张涛</em></p><p><em>　　郑州航空工业管理学院毕业，一直从事计算机应用软件的分析、设计、开发以及项目的实施，主持开发的软件包括河南省县级供电企业营销MIS、河南省在建水利工程移民资金辅助管理系统。</em></p><p>　　今天的企业信息化面临着更加具体的问题，比如终端数据如何快速采集传输; 缺乏软件应用标准，行业应用深度不够; 系统间交互性差、各自为战，资源共享程度不高; 系统具有一定规模后，维护、升级困难。由于企业在这些方面的需求非常迫切，未来各个软硬件厂商必定在这方面有所作为，基于此，笔者以为2007年以下这些技术将会有比较大的突破。</p><p>　　1. 数据采集自动化、便捷化</p><p>　　随着MCU(多点控制单元)应用范围的不断扩大，以往的各类硬件终端，比如电力、燃气、水等终端数据采集或检测设备，已经逐步从简单的计数、指示功能，向智能数据采集终端转变，而且传统装置经过简单的改造，也可实现终端数据的采集和存储，这不仅让人从数据采集的工作中解放出来，更可以通过相对廉价的手段解决采用人工采集数据所带来的一些问题。</p><p>　　正是基于这种前提，微软Office办公套件的新成员InfoPath让我们眼前一亮，借助它可以快速、方便地设计出具有超强表现力的电子凭单，以满足信息采集、企业内部和企业之间的信息传递。更令人称道的是，它不仅可以使用传统的数据库作为数据源，更可以使用XML作为数据的存储格式，让不同系统之间的数据交互更加畅通有效。</p><p>　　2. 软件插件化、框架化</p><p>　　大凡用过Eclipse的程序员都会被它的灵活和开放性所打动，而目前部分行业欠缺软件应用标准就是摆在开发商面前的诸多问题之一。类似权限管理、自定义查询、自定义报表、组织业务功能等应用系统必备的功能，完全可以通过抽象形成框架，提高代码重用度和稳定性。同时，采用软件框架进行系统的开发，不仅可以让系统分析和设计人员把主要精力放到业务模型的建立上，缩短项目周期，更可以让系统用户和开发商体会到系统稳定、维护方便、升级简单的方便。</p><p>　　在此必须要提的是Java，如果说Java的诞生是为了网络，那么可以说它已经不辱使命，而且在推动着网络技术的发展，开源性使得它的追随者们努力工作，Struts、Spring等优秀的、基于框架的作品纷至沓来，逐步让我们脱离繁杂的技术旋涡，把时间和精力投入到业务分析领域，使软件的插件化、框架化不再是海市蜃楼。</p><p>　　3. SOA</p><p>　　近几年SOA(Service-Oriented Architecture，面向服务架构)概念的提出，使得用户和软件开发商对系统建设有了新的认识。笔者认为SOA不仅是架构模型，更是一种应用思想的体现。对于软件功能粒度的划分、软件功能的部署、系统驱动模式等都会由于SOA而产生较大的影响。</p><p>　　企业通过应用SOA，不仅可以在成本没有太大增幅的条件下，让用户使用已经成熟的组件增强B2B的有效性，还可以让开发商最大限度地复用代码，把软件产品变成真正的服务。此外，SOA的实施更可以加速行业标准的制订和执行，因为只有大家遵循同样的标准和接口，才可能营造出业务共享和跨系统业务交互的良好氛围。</p><p>　　4. 虚拟软件</p><p>　　有时一些系统尤其是比较老的，对OS或DBMS有特定要求的系统，或系统在兼容性方面与新版本有差距，这时虚拟机就是最好的选择，不仅可以节省用户的硬件资源减少维护和管理成本，更可以让原有应用正常运行，为应用系统的升级换代赢得时间。与VMWore相比，微软的Virtual PC也在紧追不舍，笔者认为尽管较VMWare还有一定距离，但是无论产品孰优孰劣，最终受益的还是用户。</p><p>　　<strong>核心观点</strong></p><p>　　行业特点决定行业应用，行业应用需要软件相关技术手段提供支持，而行业应用又会引发技术的创新。</p><img src ="http://www.blogjava.net/mlh123caoer/aggbug/93333.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/mlh123caoer/" target="_blank">草儿</a> 2007-01-12 09:38 <a href="http://www.blogjava.net/mlh123caoer/archive/2007/01/12/93333.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>在Struts 2.0中国际化(i18n)您的应用程序 </title><link>http://www.blogjava.net/mlh123caoer/archive/2006/11/08/79972.html</link><dc:creator>草儿</dc:creator><author>草儿</author><pubDate>Wed, 08 Nov 2006 14:59:00 GMT</pubDate><guid>http://www.blogjava.net/mlh123caoer/archive/2006/11/08/79972.html</guid><wfw:comment>http://www.blogjava.net/mlh123caoer/comments/79972.html</wfw:comment><comments>http://www.blogjava.net/mlh123caoer/archive/2006/11/08/79972.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/mlh123caoer/comments/commentRss/79972.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/mlh123caoer/services/trackbacks/79972.html</trackback:ping><description><![CDATA[<p>国际化是商业系统中不可或缺的一部分，所以无论您学习的是什么Web框架，它都是必须掌握的技能。</p>
		<p>其实，Struts 1.x在此部分已经做得相当不错了。它极大地简化了我们程序员在做国际化时所需的工作，例如，如果您要输出一条国际化的信息，只需在代码包中加入FILE-NAME_xx_XX.properties（其中FILE-NAME为默认资源文件的文件名），然后在struts-config.xml中指明其路径，再在页面用&lt;bean:message&gt;标志输出即可。 </p>
		<p>不过，所谓“没有最好，只有更好”。Struts 2.0并没有在这部分止步，而是在原有的简单易用的基础上，将其做得更灵活、更强大。</p>
		<h2>国际化Hello World</h2>
		<p>下面让我们看一个例子——HelloWorld。这个例子演示如何根据用户浏览器的设置输出相应的HelloWorld。</p>
		<ol>
				<li>在Eclipse创建工程配置开发和运行环境（如果对这个步骤有问题，可以参考我早前的文章《<a class="entrylistItemTitle" id="A1" href="/max/archive/2006/10/10/74353.html"><strong><font color="#1a8bc8">为Struts 2.0做好准备</font></strong></a>》）。 <br /></li>
				<li>在src文件夹中加入struts.properties文件，内容如下： <br /><div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><span style="COLOR: #000000">struts.custom.i18n.resources</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">globalMessages</span></div><center><table style="BORDER-RIGHT: #f0c000 1px solid; BORDER-TOP: #f0c000 1px solid; MARGIN-TOP: 8px; MARGIN-BOTTOM: 8px; BORDER-LEFT: #f0c000 1px solid; BORDER-BOTTOM: #f0c000 1px solid; BACKGROUND-COLOR: #ffffce; TEXT-ALIGN: left" cellspacing="0" cellpadding="0" border="0"><tbody><tr><td style="PADDING-RIGHT: 4px; PADDING-LEFT: 4px; PADDING-BOTTOM: 4px; PADDING-TOP: 4px"><img src="http://cwiki.apache.org/confluence/images/icons/emoticons/lightbulb_on.gif" /></td><td style="PADDING-RIGHT: 4px; PADDING-LEFT: 4px; PADDING-BOTTOM: 4px; PADDING-TOP: 4px; FONT-FAMILY: 华文仿宋">Struts 2.0有两个配置文件，struts.xml和struts.properties都是放在WEB-INF/classes/下。 
<ul><li>struts.xml用于应用程序相关的配置 
</li><li>struts.properties用于Struts 2.0的运行时（Runtime）的配置</li></ul></td></tr></tbody></table></center></li>
				<li>在src文件夹中加入globalMessages_en_US.properties文件，内容如下：<br /><div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; MARGIN-BOTTOM: 8px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><span style="COLOR: #000000">HelloWorld</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">Hello World!</span></div></li>
				<li>在src文件夹中加入globalMessages_zh_CN.properties文件，内容如下：<br /><div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><span style="COLOR: #000000">HelloWorld</span><span style="COLOR: #000000">=你</span><span style="COLOR: #000000">好，世界！</span></div><table style="BORDER-RIGHT: #f0c000 1px solid; BORDER-TOP: #f0c000 1px solid; MARGIN-TOP: 8px; MARGIN-BOTTOM: 8px; BORDER-LEFT: #f0c000 1px solid; BORDER-BOTTOM: #f0c000 1px solid; BACKGROUND-COLOR: #ffffce; TEXT-ALIGN: left" cellspacing="0" cellpadding="0" border="0"><tbody><tr><td style="PADDING-RIGHT: 4px; PADDING-LEFT: 4px; PADDING-BOTTOM: 4px; PADDING-TOP: 4px"><img src="http://cwiki.apache.org/confluence/images/icons/emoticons/lightbulb_on.gif" /></td><td style="PADDING-RIGHT: 4px; PADDING-LEFT: 4px; PADDING-BOTTOM: 4px; PADDING-TOP: 4px; FONT-FAMILY: 华文仿宋">在此想和大家分享一个不错的编写properties文件的Eclipse插件（plugin），有了它我们在编辑一些简体中文、繁体中文等Unicode文本时，就不必再使用native2ascii编码了。您可以通过Eclipse中的软件升级（Software Update）安装此插件，步骤如下：<br /><div style="PADDING-RIGHT: 36px; PADDING-LEFT: 36px">1、展开Eclipse的Help菜单，将鼠标移到Software Update子项，在出现的子菜单中点击Find and Install；<br />2、在Install/Update对话框中选择Search for new features to install，点击Next；<br />3、在Install对话框中点击New Remote Site；<br />4、在New Update Site对话框的Name填入“PropEdit”或其它任意非空字符串，在URL中填入http://propedit.sourceforge.jp/eclipse/updates/；<br />5、在Site to include to search列表中，除上一步加入的site外的其它选项去掉，点击Finsih；<br />6、在弹出的Updates对话框中的Select the features to install列表中将所有结尾为“3.1.x”的选项去掉（适用于Eclipse 3.2版本的朋友）；<br />7、点击Finish关闭对话框；<br />8、在下载后，同意安装，再按提示重启Eclipse，在工具条看到形似vi的按钮表示安装成功，插件可用。此时，Eclpise中所有properties文件的文件名前有绿色的P的图标作为标识。 </div></td></tr></tbody></table></li>
				<li>在WebContent文件夹下加入HelloWorl.jsp文件，内容如下：<br /><div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; MARGIN-BOTTOM: 8px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><span style="COLOR: #000000; BACKGROUND-COLOR: #ffff00">&lt;%</span><span style="COLOR: #000000; BACKGROUND-COLOR: #f5f5f5">@ page  contentType</span><span style="COLOR: #000000; BACKGROUND-COLOR: #f5f5f5">=</span><span style="COLOR: #000000; BACKGROUND-COLOR: #f5f5f5">"</span><span style="COLOR: #000000; BACKGROUND-COLOR: #f5f5f5">text/html; charset=UTF-8</span><span style="COLOR: #000000; BACKGROUND-COLOR: #f5f5f5">"</span><span style="COLOR: #000000; BACKGROUND-COLOR: #ffff00">%&gt;</span><span style="COLOR: #000000"><br /></span><span style="COLOR: #000000; BACKGROUND-COLOR: #ffff00">&lt;%</span><span style="COLOR: #000000; BACKGROUND-COLOR: #f5f5f5">@taglib prefix</span><span style="COLOR: #000000; BACKGROUND-COLOR: #f5f5f5">=</span><span style="COLOR: #000000; BACKGROUND-COLOR: #f5f5f5">"</span><span style="COLOR: #000000; BACKGROUND-COLOR: #f5f5f5">s</span><span style="COLOR: #000000; BACKGROUND-COLOR: #f5f5f5">"</span><span style="COLOR: #000000; BACKGROUND-COLOR: #f5f5f5"> uri</span><span style="COLOR: #000000; BACKGROUND-COLOR: #f5f5f5">=</span><span style="COLOR: #000000; BACKGROUND-COLOR: #f5f5f5">"</span><span style="COLOR: #000000; BACKGROUND-COLOR: #f5f5f5">/struts-tags</span><span style="COLOR: #000000; BACKGROUND-COLOR: #f5f5f5">"</span><span style="COLOR: #000000; BACKGROUND-COLOR: #f5f5f5"></span><span style="COLOR: #000000; BACKGROUND-COLOR: #ffff00">%&gt;</span><span style="COLOR: #000000"><br /></span><span style="COLOR: #0000ff">&lt;</span><span style="COLOR: #800000">html</span><span style="COLOR: #0000ff">&gt;</span><span style="COLOR: #000000"><br /></span><span style="COLOR: #0000ff">&lt;</span><span style="COLOR: #800000">head</span><span style="COLOR: #0000ff">&gt;</span><span style="COLOR: #000000"><br />    </span><span style="COLOR: #0000ff">&lt;</span><span style="COLOR: #800000">title</span><span style="COLOR: #0000ff">&gt;</span><span style="COLOR: #000000">Hello World</span><span style="COLOR: #0000ff">&lt;/</span><span style="COLOR: #800000">title</span><span style="COLOR: #0000ff">&gt;</span><span style="COLOR: #000000"><br /></span><span style="COLOR: #0000ff">&lt;/</span><span style="COLOR: #800000">head</span><span style="COLOR: #0000ff">&gt;</span><span style="COLOR: #000000"><br /></span><span style="COLOR: #0000ff">&lt;</span><span style="COLOR: #800000">body</span><span style="COLOR: #0000ff">&gt;</span><span style="COLOR: #000000"><br />    </span><span style="COLOR: #0000ff">&lt;</span><span style="COLOR: #800000">h2</span><span style="COLOR: #0000ff">&gt;&lt;</span><span style="COLOR: #800000">s:text </span><span style="COLOR: #ff0000">name</span><span style="COLOR: #0000ff">="HelloWorld"</span><span style="COLOR: #ff0000"></span><span style="COLOR: #0000ff">/&gt;&lt;/</span><span style="COLOR: #800000">h2</span><span style="COLOR: #0000ff">&gt;</span><span style="COLOR: #000000"><br />    </span><span style="COLOR: #0000ff">&lt;</span><span style="COLOR: #800000">h2</span><span style="COLOR: #0000ff">&gt;&lt;</span><span style="COLOR: #800000">s:property </span><span style="COLOR: #ff0000">value</span><span style="COLOR: #0000ff">="%{getText('HelloWorld')}"</span><span style="COLOR: #ff0000"></span><span style="COLOR: #0000ff">/&gt;&lt;/</span><span style="COLOR: #800000">h2</span><span style="COLOR: #0000ff">&gt;</span><span style="COLOR: #000000"><br /></span><span style="COLOR: #0000ff">&lt;/</span><span style="COLOR: #800000">body</span><span style="COLOR: #0000ff">&gt;</span><span style="COLOR: #000000"><br /></span><span style="COLOR: #0000ff">&lt;/</span><span style="COLOR: #800000">html</span><span style="COLOR: #0000ff">&gt;</span></div></li>
				<li>发布运行应用程序，在浏览器地址栏中输入<a href="http://localhost:8080/Struts2_i18n/HelloWorld.jsp"><font color="#1a8bc8">http://localhost:8080/Struts2_i18n/HelloWorld.jsp</font></a> ，出现图1所示页面。<br /><img alt="图1 中文输出" src="http://www.blogjava.net/images/blogjava_net/max/16758/r_imag2.gif" /><br /><span style="FONT-SIZE: smaller; MARGIN-BOTTOM: 8px; FONT-STYLE: italic"><font size="1">图1 中文输出</font></span></li>
				<li>将浏览器的默认语言改为“英语（美国）”，刷新页面，出现图2所示页面。<br /><img alt="图2 英文输出" src="http://www.blogjava.net/images/blogjava_net/max/16758/r_imag1.gif" /><br /><span style="FONT-SIZE: smaller; MARGIN-BOTTOM: 8px; FONT-STYLE: italic"><font size="1">图2 英文输出</font></span></li>
		</ol>上面的例子的做法，与Struts 1.x的做法相似，似乎并不能体现Struts 2.0的优势。不过，我在上面的例子用了两种方法来显示国际化字符串，其输出是相同的。其实，这就是Struts 2.0的一个优势，因为它默认支持EL，所示我们可以用getText方法来简洁地取得国际化字符串。另外更普遍的情况——在使用UI表单标志时，getText可以用来设置label属性，例如：<br /><div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><span style="COLOR: #0000ff">&lt;</span><span style="COLOR: #800000">s:textfield </span><span style="COLOR: #ff0000">name</span><span style="COLOR: #0000ff">="name"</span><span style="COLOR: #ff0000"> label</span><span style="COLOR: #0000ff">="%{getText('UserName')}"</span><span style="COLOR: #ff0000"></span><span style="COLOR: #0000ff">/&gt;</span></div><h2>资源文件查找顺序</h2><p>之所以说Struts 2.0的国际化更灵活是因为它可以能根据不同需要配置和获取资源（properties）文件。在Struts 2.0中有下面几种方法：</p><ol><li>使用全局的资源文件，方法如上例所示。这适用于遍布于整个应用程序的国际化字符串，它们在不同的包（package）中被引用，如一些比较共用的出错提示； 
</li><li>使用包范围内的资源文件。做法是在包的根目录下新建名的package.properties和package_xx_XX.properties文件。这就适用于在包中不同类访问的资源； 
</li><li>使用Action范围的资源文件。做法为Action的包下新建文件名（除文件扩展名外）与Action类名同样的资源文件。它只能在该Action中访问。如此一来，我们就可以在不同的Action里使用相同的properties名表示不同的值。例如，在ActonOne中title为“动作一”，而同样用title在ActionTwo表示“动作二”，节省一些命名工夫； 
</li><li>使用&lt;s:i18n&gt;标志访问特定路径的properties文件。使用方法请参考我早前的文章《<a class="entrylistItemTitle" id="CategoryEntryList1_EntryStoryList_Entries_ctl02_TitleUrl" href="/max/archive/2006/10/18/75857.html"><strong><font color="#1a8bc8">常用的Struts 2.0的标志（Tag）介绍</font></strong></a>》。在您使用这一方法时，请注意&lt;s:i18n&gt;标志的范围。在&lt;s:i18n name="xxxxx"&gt;到&lt;/s:i18n&gt;之间，所有的国际化字符串都会在名为xxxxx资源文件查找，如果找不到，Struts 2.0就会输出默认值（国际化字符串的名字）。</li></ol><p>上面我列举了四种配置和访问资源的方法，它们的范围分别是从大到小，而Struts 2.0在查找国际化字符串所遵循的是特定的顺序，如图3所示：</p><img alt="图3 资源文件查找顺序图" src="http://www.blogjava.net/images/blogjava_net/max/16758/o_Search.jpg" /><br /><span style="FONT-SIZE: smaller; MARGIN-BOTTOM: 8px; FONT-STYLE: italic"><font size="1">图3 资源文件查找顺序图</font></span><p>假设我们在某个ChildAction中调用了getText("user.title")，Struts 2.0的将会执行以下的操作： </p><ol><li>查找ChildAction_xx_XX.properties文件或ChildAction.properties； 
</li><li>查找ChildAction实现的接口，查找与接口同名的资源文件MyInterface.properties； 
</li><li>查找ChildAction的父类ParentAction的properties文件，文件名为ParentAction.properties； 
</li><li>判断当前ChildAction是否实现接口ModelDriven。如果是，调用getModel()获得对象，查找与其同名的资源文件； 
</li><li>查找当前包下的package.properties文件； 
</li><li>查找当前包的父包，直到最顶层包； 
</li><li>在值栈（Value Stack）中，查找名为user的属性，转到user类型同名的资源文件，查找键为title的资源; 
</li><li>查找在struts.properties配置的默认的资源文件，参考例1; 
</li><li>输出user.title。</li></ol><h2>参数化国际化字符串</h2><p>许多情况下，我们都需要在动行时（runtime）为国际化字符插入一些参数，例如在输入验证提示信息的时候。在Struts 2.0中，我们通过以下两种方法做到这点：</p><ol><li>在资源文件的国际化字符串中使用OGNL，格式为${表达式}，例如：<br /><div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; MARGIN-BOTTOM: 8px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><span style="COLOR: #000000">validation.require</span><span style="COLOR: #000000">=</span><span style="MARGIN-BOTTOM: 8px; COLOR: #000000">${getText(fileName)} is required</span></div></li><li>使用<a href="http://gceclub.sun.com.cn/Java_Docs/html/zh_CN/api/java/text/MessageFormat.html"><font color="#1a8bc8">java.text.MessageFormat</font></a>中的字符串格式，格式为{ 参数序号（从0开始）, 格式类形（number | date | time | choice）, 格式样式}，例如：<br /><div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><span style="COLOR: #000000">validation.between</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">Date must between {</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">,</span><span style="COLOR: #000000"> date, short} and {</span><span style="COLOR: #000000">1</span><span style="COLOR: #000000">,</span><span style="COLOR: #000000"> date, short}</span></div></li></ol>在显示这些国际化字符时，同样有两种方法设置参数的值：<br /><ol><li>使用标志的value0、value1...valueN的属性，如：<br /><div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; MARGIN-BOTTOM: 8px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><span style="COLOR: #0000ff">&lt;</span><span style="COLOR: #800000">s:text </span><span style="COLOR: #ff0000">name</span><span style="COLOR: #0000ff">="validation.required"</span><span style="COLOR: #ff0000"> value0</span><span style="COLOR: #0000ff">="User Name"</span><span style="COLOR: #ff0000"></span><span style="COLOR: #0000ff">/&gt;</span></div></li><li>使用param子元素，这些param将按先后顺序，代入到国际化字符串的参数中，例如：<br /><div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><span style="COLOR: #0000ff">&lt;</span><span style="COLOR: #800000">s:text </span><span style="COLOR: #ff0000">name</span><span style="COLOR: #0000ff">="validation.required"</span><span style="COLOR: #0000ff">&gt;</span><span style="COLOR: #000000"><br />   </span><span style="COLOR: #0000ff">&lt;</span><span style="COLOR: #800000">s:param </span><span style="COLOR: #ff0000">value</span><span style="COLOR: #0000ff">="User Name"</span><span style="COLOR: #ff0000"></span><span style="COLOR: #0000ff">/&gt;</span><span style="COLOR: #000000"><br /></span><span style="COLOR: #0000ff">&lt;/</span><span style="COLOR: #800000">s:text</span><span style="COLOR: #0000ff">&gt;</span></div></li></ol><h2>让用户方便地选择语言</h2><p>开发国际化的应用程序时，有一个功能是必不可少的——让用户快捷地选择或切换语言。在Struts 2.0中，通过ActionContext.getContext().setLocale(Locale arg)可以设置用户的默认语言。不过，由于这是一个比较普遍的应用场景（Scenario），所以Struts 2.0为您提供了一个名i18n的拦截器（Interceptor），并在默认情况下将其注册到拦截器链（Interceptor chain）中。它的原理为在执行Action方法前，i18n拦截器查找请求中的一个名为"request_locale"的参数。如果其存在，拦截器就将其作为参数实例化Locale对象，并将其设为用户默认的区域（Locale），最后，将此Locale对象保存在session的名为“WW_TRANS_I18N_LOCALE”的属性中。</p><p>下面，我将提供一完整示例演示它的使用方法。</p><div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" /><span style="COLOR: #0000ff">package</span><span style="COLOR: #000000"> tutorial;<br /><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" /><br /><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" /></span><span style="COLOR: #0000ff">import</span><span style="COLOR: #000000"> java.util.Hashtable;<br /><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" /></span><span style="COLOR: #0000ff">import</span><span style="COLOR: #000000"> java.util.Locale;<br /><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" /></span><span style="COLOR: #0000ff">import</span><span style="COLOR: #000000"> java.util.Map;<br /><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" /><br /><img id="Codehighlighter1_116_345_Open_Image" onclick="this.style.display='none'; Codehighlighter1_116_345_Open_Text.style.display='none'; Codehighlighter1_116_345_Closed_Image.style.display='inline'; Codehighlighter1_116_345_Closed_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ExpandedBlockStart.gif" align="top" /><img id="Codehighlighter1_116_345_Closed_Image" style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_116_345_Closed_Text.style.display='none'; Codehighlighter1_116_345_Open_Image.style.display='inline'; Codehighlighter1_116_345_Open_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ContractedBlock.gif" align="top" /></span><span style="COLOR: #0000ff">public</span><span style="COLOR: #000000"></span><span style="COLOR: #0000ff">class</span><span style="COLOR: #000000"> Locales </span><span id="Codehighlighter1_116_345_Closed_Text" style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.blogjava.net/images/dot.gif" /></span><span id="Codehighlighter1_116_345_Open_Text"><span style="COLOR: #000000">{<br /><img id="Codehighlighter1_159_343_Open_Image" onclick="this.style.display='none'; Codehighlighter1_159_343_Open_Text.style.display='none'; Codehighlighter1_159_343_Closed_Image.style.display='inline'; Codehighlighter1_159_343_Closed_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ExpandedSubBlockStart.gif" align="top" /><img id="Codehighlighter1_159_343_Closed_Image" style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_159_343_Closed_Text.style.display='none'; Codehighlighter1_159_343_Open_Image.style.display='inline'; Codehighlighter1_159_343_Open_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ContractedSubBlock.gif" align="top" />    </span><span style="COLOR: #0000ff">public</span><span style="COLOR: #000000"> Map</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000">String, Locale</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000"> getLocales() </span><span id="Codehighlighter1_159_343_Closed_Text" style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.blogjava.net/images/dot.gif" /></span><span id="Codehighlighter1_159_343_Open_Text"><span style="COLOR: #000000">{<br /><img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top" />        Map</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000">String, Locale</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000"> locales </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"></span><span style="COLOR: #0000ff">new</span><span style="COLOR: #000000"> Hashtable</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000">String, Locale</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000">(</span><span style="COLOR: #000000">2</span><span style="COLOR: #000000">);<br /><img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top" />        locales.put(</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">American English</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">, Locale.US);<br /><img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top" />        locales.put(</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">Simplified Chinese</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">, Locale.CHINA);<br /><img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top" />        </span><span style="COLOR: #0000ff">return</span><span style="COLOR: #000000"> locales;<br /><img src="http://www.blogjava.net/images/OutliningIndicators/ExpandedSubBlockEnd.gif" align="top" />    }</span></span><span style="COLOR: #000000"><br /><img src="http://www.blogjava.net/images/OutliningIndicators/ExpandedBlockEnd.gif" align="top" />}</span></span></div><font size="1"><span style="FONT-SIZE: smaller; FONT-STYLE: italic">tutorial/Locales.java</span><br /><br /></font><div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><span style="COLOR: #000000; BACKGROUND-COLOR: #ffff00">&lt;%</span><span style="COLOR: #000000; BACKGROUND-COLOR: #f5f5f5">@taglib prefix</span><span style="COLOR: #000000; BACKGROUND-COLOR: #f5f5f5">=</span><span style="COLOR: #000000; BACKGROUND-COLOR: #f5f5f5">"</span><span style="COLOR: #000000; BACKGROUND-COLOR: #f5f5f5">s</span><span style="COLOR: #000000; BACKGROUND-COLOR: #f5f5f5">"</span><span style="COLOR: #000000; BACKGROUND-COLOR: #f5f5f5"> uri</span><span style="COLOR: #000000; BACKGROUND-COLOR: #f5f5f5">=</span><span style="COLOR: #000000; BACKGROUND-COLOR: #f5f5f5">"</span><span style="COLOR: #000000; BACKGROUND-COLOR: #f5f5f5">/struts-tags</span><span style="COLOR: #000000; BACKGROUND-COLOR: #f5f5f5">"</span><span style="COLOR: #000000; BACKGROUND-COLOR: #f5f5f5"></span><span style="COLOR: #000000; BACKGROUND-COLOR: #ffff00">%&gt;</span><span style="COLOR: #000000"><br /></span><span style="COLOR: #0000ff">&lt;</span><span style="COLOR: #800000">script </span><span style="COLOR: #ff0000">type</span><span style="COLOR: #0000ff">="text/javascript"</span><span style="COLOR: #0000ff">&gt;</span><span style="COLOR: #000000; BACKGROUND-COLOR: #f5f5f5"><br /></span><span style="COLOR: #000000; BACKGROUND-COLOR: #f5f5f5">&lt;!--</span><span style="COLOR: #000000; BACKGROUND-COLOR: #f5f5f5"><br />    </span><span style="COLOR: #0000ff; BACKGROUND-COLOR: #f5f5f5">function</span><span style="COLOR: #000000; BACKGROUND-COLOR: #f5f5f5"> langSelecter_onChanged() {<br />        document.langForm.submit();<br />    }<br /></span><span style="COLOR: #008000; BACKGROUND-COLOR: #f5f5f5">//</span><span style="COLOR: #008000; BACKGROUND-COLOR: #f5f5f5">--&gt;</span><span style="COLOR: #008000; BACKGROUND-COLOR: #f5f5f5"><br /></span><span style="COLOR: #0000ff">&lt;/</span><span style="COLOR: #800000">script</span><span style="COLOR: #0000ff">&gt;</span><span style="COLOR: #000000"><br /></span><span style="COLOR: #0000ff">&lt;</span><span style="COLOR: #800000">s:set </span><span style="COLOR: #ff0000">name</span><span style="COLOR: #0000ff">="SESSION_LOCALE"</span><span style="COLOR: #ff0000"> value</span><span style="COLOR: #0000ff">="#session['WW_TRANS_I18N_LOCALE']"</span><span style="COLOR: #ff0000"></span><span style="COLOR: #0000ff">/&gt;</span><span style="COLOR: #000000"><br /></span><span style="COLOR: #0000ff">&lt;</span><span style="COLOR: #800000">s:bean </span><span style="COLOR: #ff0000">id</span><span style="COLOR: #0000ff">="locales"</span><span style="COLOR: #ff0000"> name</span><span style="COLOR: #0000ff">="tutorial.Locales"</span><span style="COLOR: #ff0000"></span><span style="COLOR: #0000ff">/&gt;</span><span style="COLOR: #000000"><br /></span><span style="COLOR: #0000ff">&lt;</span><span style="COLOR: #800000">form </span><span style="COLOR: #ff0000">action</span><span style="COLOR: #0000ff">="&lt;s:url includeParams="</span><span style="COLOR: #ff0000">get" encode</span><span style="COLOR: #0000ff">="true"</span><span style="COLOR: #ff0000"></span><span style="COLOR: #0000ff">/&gt;</span><span style="COLOR: #000000">" name="langForm" <br />    style="background-color: powderblue; padding-top: 4px; padding-bottom: 4px;"&gt;<br />    Language: </span><span style="COLOR: #0000ff">&lt;</span><span style="COLOR: #800000">s:select </span><span style="COLOR: #ff0000">label</span><span style="COLOR: #0000ff">="Language"</span><span style="COLOR: #ff0000"> <br />        list</span><span style="COLOR: #0000ff">="#locales.locales"</span><span style="COLOR: #ff0000"> listKey</span><span style="COLOR: #0000ff">="value"</span><span style="COLOR: #ff0000">    listValue</span><span style="COLOR: #0000ff">="key"</span><span style="COLOR: #ff0000"><br />        value</span><span style="COLOR: #0000ff">="#SESSION_LOCALE == null ? locale : #SESSION_LOCALE"</span><span style="COLOR: #ff0000"><br />        name</span><span style="COLOR: #0000ff">="request_locale"</span><span style="COLOR: #ff0000"> id</span><span style="COLOR: #0000ff">="langSelecter"</span><span style="COLOR: #ff0000"> <br />        onchange</span><span style="COLOR: #0000ff">="langSelecter_onChanged()"</span><span style="COLOR: #ff0000"> theme</span><span style="COLOR: #0000ff">="simple"</span><span style="COLOR: #ff0000"></span><span style="COLOR: #0000ff">/&gt;</span><span style="COLOR: #000000"><br /></span><span style="COLOR: #0000ff">&lt;/</span><span style="COLOR: #800000">form</span><span style="COLOR: #0000ff">&gt;</span></div><span style="FONT-SIZE: smaller; FONT-STYLE: italic"><font size="1">LangSelector.jsp</font></span><p>上述代码的原理为，LangSelector.jsp先实例化一个Locales对象，并把对象的Map类型的属性locales赋予下拉列表（select） 。如此一来，下拉列表就获得可用语言的列表。大家看到LangSelector有&lt;s:form&gt;标志和一段Javascript脚本，它们的作用就是在用户在下拉列表中选择了后，提交包含“reqeust_locale”变量的表单到Action。在打开页面时，为了下拉列表的选中的当前区域，我们需要到session取得当前区域（键为“WW_TRANS_I18N_LOCALE”的属性），而该属性在没有设置语言前是为空的，所以通过值栈中locale属性来取得当前区域（用户浏览器所设置的语言）。</p>你可以把LangSelector.jsp作为一个控件使用，方法是在JSP页面中把它包含进来，代码如下所示： 
<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><span style="COLOR: #0000ff">&lt;</span><span style="COLOR: #800000">s:include </span><span style="COLOR: #ff0000">value</span><span style="COLOR: #0000ff">="/LangSelector.jsp"</span><span style="COLOR: #ff0000"></span><span style="COLOR: #0000ff">/&gt;</span></div><br />在例1中的HellloWorld.jsp中&lt;body&gt;后加入上述代码，并在struts.xml中新建Action，代码如下：<br /><div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><span style="COLOR: #0000ff">&lt;</span><span style="COLOR: #800000">action </span><span style="COLOR: #ff0000">name</span><span style="COLOR: #0000ff">="HelloWorld"</span><span style="COLOR: #0000ff">&gt;</span><span style="COLOR: #000000"><br />    </span><span style="COLOR: #0000ff">&lt;</span><span style="COLOR: #800000">result</span><span style="COLOR: #0000ff">&gt;</span><span style="COLOR: #000000">/HelloWorld.jsp</span><span style="COLOR: #0000ff">&lt;/</span><span style="COLOR: #800000">result</span><span style="COLOR: #0000ff">&gt;</span><span style="COLOR: #000000"><br /></span><span style="COLOR: #0000ff">&lt;/</span><span style="COLOR: #800000">action</span><span style="COLOR: #0000ff">&gt;</span></div><br />或者，如果你多个JSP需要实现上述功能，你可以使用下面的通用配置，而不是为每一个JSP页面都新建一个Action。<br /><div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><span style="COLOR: #0000ff">&lt;</span><span style="COLOR: #800000">action </span><span style="COLOR: #ff0000">name</span><span style="COLOR: #0000ff">="*"</span><span style="COLOR: #0000ff">&gt;</span><span style="COLOR: #000000"><br />    </span><span style="COLOR: #0000ff">&lt;</span><span style="COLOR: #800000">result</span><span style="COLOR: #0000ff">&gt;</span><span style="COLOR: #000000">/{1}.jsp</span><span style="COLOR: #0000ff">&lt;/</span><span style="COLOR: #800000">result</span><span style="COLOR: #0000ff">&gt;</span><span style="COLOR: #000000"><br /></span><span style="COLOR: #0000ff">&lt;/</span><span style="COLOR: #800000">action</span><span style="COLOR: #0000ff">&gt;</span></div><br />分布运行程序，在浏览器的地址栏中输入<a href="http://localhost:8080/Struts2_i18n/HelloWorld.action"><font color="#1a8bc8">http://localhost:8080/Struts2_i18n/HelloWorld.action</font></a>，出现图4所示页面：<br /><img alt="图3 HelloWorld.action" src="http://www.blogjava.net/images/blogjava_net/max/16758/r_imag3.gif" /><br /><font size="1"><span style="FONT-SIZE: smaller; MARGIN-BOTTOM: 8px; FONT-STYLE: italic">图3 HelloWorld.action<br /></span><br /></font>在下拉列表中，选择“American English”，出现图5所示页面：<br /><img alt="图3 HelloWorld.action" src="http://www.blogjava.net/images/blogjava_net/max/16758/r_imag4.gif" /><br /><font size="1"><span style="FONT-SIZE: smaller; MARGIN-BOTTOM: 8px; FONT-STYLE: italic">图4 HelloWorld.action</span><br /></font><table style="BORDER-RIGHT: #f0c000 1px solid; BORDER-TOP: #f0c000 1px solid; MARGIN-TOP: 8px; MARGIN-BOTTOM: 8px; BORDER-LEFT: #f0c000 1px solid; BORDER-BOTTOM: #f0c000 1px solid; BACKGROUND-COLOR: #ffffce; TEXT-ALIGN: left" cellspacing="0" cellpadding="0" border="0"><tbody><tr><td style="PADDING-RIGHT: 4px; PADDING-LEFT: 4px; PADDING-BOTTOM: 4px; PADDING-TOP: 4px"><font size="1"><img src="http://cwiki.apache.org/confluence/images/icons/emoticons/lightbulb_on.gif" /></font></td><td style="PADDING-RIGHT: 4px; PADDING-LEFT: 4px; PADDING-BOTTOM: 4px; PADDING-TOP: 4px; FONT-FAMILY: 华文仿宋">可能大家会问为什么一定要通过Action来访问页面呢？<br />你可以试一下不用Action而直接用JSP的地址来访问页面，结果会是无论你在下拉列表中选择什么，语言都不会改变。这表示不能正常运行的。其原因为如果直接使用JSP访问页面，Struts 2.0在web.xml的配置的过滤器（Filter）就不会工作，所以拦截器链也不会工作。</td></tr></tbody></table><div class="postDesc">posted on 2006-11-01 19:06 <a href="/max/"><font color="#1a8bc8">Max</font></a> 阅读(724) <a href="/max/archive/2006/11/01/78536.html#Post"><font color="#1a8bc8">评论(11)</font></a>  <a href="/max/admin/EditPosts.aspx?postid=78536"><font color="#1a8bc8">编辑</font></a> <a href="/max/AddToFavorite.aspx?id=78536"><font color="#1a8bc8">收藏</font></a><a href="/max/services/trackbacks/78536.aspx"><font color="#1a8bc8">引用</font></a><a href="javascript:d=document;t=d.selection?(d.selection.type!='None'?d.selection.createRange().text:''):(d.getSelection?d.getSelection():'');void(keyit=window.open('http://www.365key.com/storeit.aspx?t='+escape(d.title)+'&amp;u='+escape(d.location.href)+'&amp;c='+escape(t),'keyit','scrollbars=no,width=475,height=575,left=75,top=20,status=no,resizable=yes'));keyit.focus();"><font color="#1a8bc8">收藏至365Key</font></a> 所属分类: <a href="/max/category/16130.html"><font color="#1a8bc8">Struts 2.0系列</font></a></div><img src ="http://www.blogjava.net/mlh123caoer/aggbug/79972.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/mlh123caoer/" target="_blank">草儿</a> 2006-11-08 22:59 <a href="http://www.blogjava.net/mlh123caoer/archive/2006/11/08/79972.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>深入浅出Java设计模式之备忘录模式</title><link>http://www.blogjava.net/mlh123caoer/archive/2006/02/16/30902.html</link><dc:creator>草儿</dc:creator><author>草儿</author><pubDate>Thu, 16 Feb 2006 01:08:00 GMT</pubDate><guid>http://www.blogjava.net/mlh123caoer/archive/2006/02/16/30902.html</guid><wfw:comment>http://www.blogjava.net/mlh123caoer/comments/30902.html</wfw:comment><comments>http://www.blogjava.net/mlh123caoer/archive/2006/02/16/30902.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/mlh123caoer/comments/commentRss/30902.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/mlh123caoer/services/trackbacks/30902.html</trackback:ping><description><![CDATA[<STRONG>一、引子 <BR><BR></STRONG>　　俗话说：世上难买后悔药。所以凡事讲究个“三思而后行”，但总常见有人做“痛心疾首”状：当初我要是……。如果真的有《大话西游》中能时光倒流的“月光宝盒”，那这世上也许会少一些伤感与后悔——当然这只能是痴人说梦了。<BR><BR>　　但是在我们手指下的程序世界里，却有的后悔药买。今天我们要讲的备忘录模式便是程序世界里的“月光宝盒”。<BR><BR>　　<B>二、定义与结构</B><BR><BR>　　备忘录（Memento）模式又称标记（Token）模式。GOF给备忘录模式的定义为：在不破坏封装性的前提下，捕获一个对象的内部状态，并在该对象之外保存这个状态。这样以后就可将该对象恢复到原先保存的状态。<BR><BR>　　在讲命令模式的时候，我们曾经提到利用中间的命令角色可以实现undo、redo的功能。从定义可以看出备忘录模式是专门来存放对象历史状态的，这对于很好的实现undo、redo功能有很大的帮助。所以在命令模式中undo、redo功能可以配合备忘录模式来实现。<BR><BR>　　其实单就实现保存一个对象在某一时刻的状态的功能，还是很简单的——将对象中要保存的属性放到一个专门管理备份的对象中，需要的时候则调用约定好的方法将备份的属性放回到原来的对象中去。但是你要好好看看为了能让你的备份对象访问到原对象中的属性，是否意味着你就要全部公开或者包内公开对象原本私有的属性呢？如果你的做法已经破坏了封装，那么就要考虑重构一下了。<BR><BR>　　备忘录模式只是GOF对“恢复对象某时的原有状态”这一问题提出的通用方案。因此在如何保持封装性上——由于受到语言特性等因素的影响，备忘录模式并没有详细描述，只是基于C++阐述了思路。那么基于Java的应用应该怎样来保持封装呢？我们将在实现一节里面讨论。<BR><BR>　　来看下“月光宝盒”备忘录模式的组成部分：<BR><BR>　　1) 备忘录（Memento）角色：备忘录角色存储“备忘发起角色”的内部状态。“备忘发起角色”根据需要决定备忘录角色存储“备忘发起角色”的哪些内部状态。为了防止“备忘发起角色”以外的其他对象访问备忘录。备忘录实际上有两个接口，“备忘录管理者角色”只能看到备忘录提供的窄接口——对于备忘录角色中存放的属性是不可见的。“备忘发起角色”则能够看到一个宽接口——能够得到自己放入备忘录角色中属性。 <BR><BR>　　2) 备忘发起（Originator）角色：“备忘发起角色”创建一个备忘录，用以记录当前时刻它的内部状态。在需要时使用备忘录恢复内部状态。<BR><BR>　　3) 备忘录管理者（Caretaker）角色：负责保存好备忘录。不能对备忘录的内容进行操作或检查。<BR><BR>　　备忘录模式的类图真是再简单不过了：<BR><BR>
<TABLE width="90%" align=center border=0>
<TBODY>
<TR>
<TD>
<DIV align=center><IMG style="CURSOR: pointer" onclick=javascript:window.open(this.src); src="http://dev.yesky.com/imagelist/05/08/um649oea69lz.jpg" onload="javascript:if(this.width>500)this.style.width=500;"></DIV></TD></TR></TBODY></TABLE><BR>　　<B>三、举例</B><BR><BR>　　按照定义中的要求，备忘录角色要保持完整的封装。最好的情况便是：备忘录角色只应该暴露操作内部存储属性的的接口给“备忘发起角色”。而对于其他角色则是不可见的。GOF在书中以C++为例进行了探讨。但是在Java中没有提供类似于C++中友元的概念。在Java中怎样才能保持备忘录角色的封装呢？<BR><BR>　　下面对三种在Java中可保存封装的方法进行探讨。<BR><BR>　　第一种就是采用两个不同的接口类来限制访问权限。这两个接口类中，一个提供比较完备的操作状态的方法，我们称它为宽接口；而另一个则可以只是一个标示，我们称它为窄接口。备忘录角色要实现这两个接口类。这样对于“备忘发起角色”采用宽接口进行访问，而对于其他的角色或者对象则采用窄接口进行访问。<BR><BR>　　这种实现比较简单，但是需要人为的进行规范约束——而这往往是没有力度的。<BR><BR>　　第二种方法便很好的解决了第一种的缺陷：采用内部类来控制访问权限。将备忘录角色作为“备忘发起角色”的一个私有内部类。好处我不详细解释了，看看代码吧就明白了。下面的代码是一个完整的备忘录模式的教学程序。它便采用了第二种方法来实现备忘录模式。<BR><BR>　　还有一点值得指出的是，在下面的代码中，对于客户程序来说“备忘录管理者角色”是不可见的，这样简化了客户程序使用备忘录模式的难度。下面采用“备忘发起角色”来调用访问“备忘录管理者角色”，也可以参考门面模式在客户程序与备忘录角色之间添加一个门面角色。<BR><BR>
<TABLE borderColor=#cccccc width="90%" align=center bgColor=#e3e3e3 border=1>
<TBODY>
<TR>
<TD>　class Originator{<BR><BR>　　//这个是要保存的状态 <BR>　　private int state= 90;<BR>　　//保持一个“备忘录管理者角色”的对象<BR>　　private Caretaker c = new Caretaker();<BR>　　//读取备忘录角色以恢复以前的状态<BR>　　public void setMemento(){<BR>　　　Memento memento = (Memento)c.getMemento();<BR>　　　state = memento.getState(); <BR>　　　System.out.println("the state is "+state+" now");<BR>　　}<BR>　　//创建一个备忘录角色，并将当前状态属性存入，托给“备忘录管理者角色”存放。<BR><BR>　　public void createMemento(){<BR>　　　c.saveMemento(new Memento(state)); <BR>　　}<BR>　　//this is other business methods...<BR>　　//they maybe modify the attribute state <BR><BR>　　public void modifyState4Test(int m){<BR>　　　state = m;<BR>　　　System.out.println("the state is "+state+" now");<BR>　　} <BR><BR>　　//作为私有内部类的备忘录角色，它实现了窄接口，可以看到在第二种方法中宽接口已经不再需要<BR>　　//注意：里面的属性和方法都是私有的<BR><BR>　　private class Memento implements MementoIF{<BR>　　　private int state ;<BR>　　　private Memento(int state){<BR>　　　　this.state = state ; <BR>　　　}<BR><BR>　　　private int getState(){<BR>　　　　return state; <BR>　　　} <BR>　　}<BR>　}<BR><BR>　//测试代码——客户程序<BR><BR>　public class TestInnerClass{<BR>　　public static void main(String[] args){<BR>　　　Originator o = new Originator(); <BR>　　　o.createMemento();<BR>　　　o.modifyState4Test(80);<BR>　　　o.setMemento();<BR>　　}<BR>　}<BR><BR>　//窄接口<BR><BR>　interface MementoIF{}<BR><BR>　//“备忘录管理者角色”<BR><BR>　class Caretaker{<BR>　　private MementoIF m ;<BR>　　public void saveMemento(MementoIF m){<BR>　　　this.m = m; <BR>　　}<BR>　　public MementoIF getMemento(){<BR>　　　return m; <BR>　　}<BR>　}<BR></TD></TR></TBODY></TABLE><BR>　　第三种方式是不太推荐使用的：使用clone方法来简化备忘录模式。由于Java提供了clone机制，这使得复制一个对象变得轻松起来。使用了clone机制的备忘录模式，备忘录角色基本可以省略了，而且可以很好的保持对象的封装。但是在为你的类实现clone方法时要慎重啊。<BR><BR>　　在上面的教学代码中，我们简单的模拟了备忘录模式的整个流程。在实际应用中，我们往往需要保存大量“备忘发起角色”的历史状态。这时就要对我们的“备忘录管理者角色”进行改造，最简单的方式就是采用容器来按照顺序存放备忘录角色。这样就可以很好的实现undo、redo功能了。<BR><BR>　　<B>四、适用情况</B><BR><BR>　　从上面的讨论可以看出，使用了备忘录模式来实现保存对象的历史状态可以有效地保持封装边界。使用备忘录可以避免暴露一些只应由“备忘发起角色”管理却又必须存储在“备忘发起角色”之外的信息。把“备忘发起角色”内部信息对其他对象屏蔽起来, 从而保持了封装边界。<BR><BR>　　但是如果备份的“备忘发起角色”存在大量的信息或者创建、恢复操作非常频繁，则可能造成很大的开销。<BR><BR>　　GOF在《设计模式》中总结了使用备忘录模式的前提： <BR><BR>　　1) 必须保存一个对象在某一个时刻的(部分)状态, 这样以后需要时它才能恢复到先前的状态。<BR><BR>　　2) 如果一个用接口来让其它对象直接得到这些状态，将会暴露对象的实现细节并破坏对象的封装性。<BR><BR>　　<B>五、总结</B><BR><BR>　　介绍了怎样来使用备忘录模式实现存储对象历史状态的功能，并对基于Java的实现进行了讨论。欢迎大家指正。<BR><img src ="http://www.blogjava.net/mlh123caoer/aggbug/30902.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/mlh123caoer/" target="_blank">草儿</a> 2006-02-16 09:08 <a href="http://www.blogjava.net/mlh123caoer/archive/2006/02/16/30902.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>适配器模式（Adapter Pattern）</title><link>http://www.blogjava.net/mlh123caoer/archive/2006/02/16/30901.html</link><dc:creator>草儿</dc:creator><author>草儿</author><pubDate>Thu, 16 Feb 2006 01:06:00 GMT</pubDate><guid>http://www.blogjava.net/mlh123caoer/archive/2006/02/16/30901.html</guid><wfw:comment>http://www.blogjava.net/mlh123caoer/comments/30901.html</wfw:comment><comments>http://www.blogjava.net/mlh123caoer/archive/2006/02/16/30901.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/mlh123caoer/comments/commentRss/30901.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/mlh123caoer/services/trackbacks/30901.html</trackback:ping><description><![CDATA[适配器模式（Adapter&nbsp;Pattern）<BR>
<H3>说明：</H3><BR>&nbsp;&nbsp;&nbsp;&nbsp;通常，客户类（clients&nbsp;of&nbsp;class）通过类的接口访问它提供的服务。有时，现有的类（existing&nbsp;class）可以提供客户类的功能需要，但是它所提供的接口不一定是客户类所期望的。这是由于现有的接口太详细或者缺乏详细或接口的名称与客户类所查找的不同等诸多不同原因导致的。<BR>在这种情况下，现有的接口需要转化（convert）为客户类期望的接口，这样保证了对现有类的重用。如果不进行这样的转化，客户类就不能利用现有类所提供的功能。适配器模式（Adapter&nbsp;Pattern）可以完成这样的转化。适配器模式建议定义一个包装类，包装有不兼容接口的对象。这个包装类指的就是适配器（Adapter），它包装的对象就是适配者(Adaptee)。适配器提供客户类需要的接口，适配器接口的实现是把客户类的请求转化为对适配者的相应接口的调用。换句话说：当客户类调用适配器的方法时，在适配器类的内部调用适配者类的方法，这个过程对客户类是透明的，客户类并不直接访问适配者类。因此，适配器可以使由于借口不兼容而不能交互的类可以一起工作（work&nbsp;together）。<BR>在上面讨论的接口：<BR>（1）&nbsp;&nbsp;&nbsp;&nbsp;不是指在JAVA编程语言中接口的概念，虽然类的接口可以通过JAVA借扩来定义。<BR>（2）&nbsp;&nbsp;&nbsp;&nbsp;不是指由窗体和GUI控件所组成的GUI应用程序的用户接口。<BR>（3）&nbsp;&nbsp;&nbsp;&nbsp;而是指类所报漏的，被其他类调用的编程接口，<BR>类适配器（Class&nbsp;Adapter）VS对象适配器(Object&nbsp;Adapter)<BR>适配器总体上可以分为两类??类适配器（Class&nbsp;Adapter）VS对象适配器(Object&nbsp;Adapter)<BR>&nbsp;&nbsp;&nbsp;&nbsp; 
<H4>类适配器：</H4><BR>&nbsp;&nbsp;&nbsp;&nbsp;类适配器是通过继承类适配者类（Adaptee&nbsp;Class）实现的，另外类适配器实现客户类所需要的接口。当客户对象调用适配器类方法的时候，适配器内部调用它所继承的适配者的方法。<BR>&nbsp;&nbsp;&nbsp;&nbsp; 
<H4>对象适配器：</H4><BR>&nbsp;&nbsp;&nbsp;&nbsp;对象适配器包含一个适配器者的引用（reference），与类适配器相同，对象适配器也实现了客户类需要的接口。当客户对象调用对象适配器的方法的时候，对象适配器调它所包含的适配器者实例的适当方法。<BR>下表是类适配器（Class&nbsp;Adapter）和对象适配器(Object&nbsp;Adapter)的详细不同：<BR><IMG style="CURSOR: pointer" onclick=javascript:window.open(this.src); src="http://www.javaresearch.org/members/stoneWindow/20.0.1.bmp" onload="javascript:if(this.width>500)this.style.width=500;"><BR>类适配器（Class&nbsp;Adapter）&nbsp;&nbsp;&nbsp;&nbsp;对象适配器(Object&nbsp;Adapter)<BR>基于继承概念&nbsp;&nbsp;&nbsp;&nbsp;利用对象合成<BR>只能应用在适配者是接口，不能利用它子类的接口，当类适配器建立时，它就静态地与适配者关联&nbsp;&nbsp;&nbsp;&nbsp;可以应用在适配者是接口和它的所有子类<BR>因为适配器是作为适配者的子类，所以适配器可能会重载适配者的一些行为。<BR>注意：在JAVA中，子类不能重载父类中声明为final的方法。&nbsp;&nbsp;&nbsp;&nbsp;不能重载适配者的方法。<BR>注意:字面上，不能重栽只是因为没有继承。但是适配器提供包装方法可以按需要改变行为。<BR>客户类对适配者中声明为public的接口是可见的，&nbsp;&nbsp;&nbsp;&nbsp;客户类和适配者是完全不关联的，只有适配器才能感知适配者接口。<BR>在JAVA应用程序中：<BR>适用于期待的接口是JAVA接口的形式，而不是抽象地或具体地类的形式。这是因为<BR>JAVA编程语言只允许单继承。因此，类适配器设计成适配者的子类。&nbsp;&nbsp;&nbsp;&nbsp;在JAVA应用程序中：<BR>适用于当客户对象期望的接口是抽象类的形式，同时也可以应用于期望接口是Java接口的形式。<BR>&nbsp;&nbsp;&nbsp;&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;<BR>例子：<BR>让我们建立一个验证给定客户地址的应用。这个应用是作为大的客户数据管理应用的一部分。<BR>让我们定义一个Customer类：<BR>Customer&nbsp;<BR><IMG style="CURSOR: pointer" onclick=javascript:window.open(this.src); src="http://www.javaresearch.org/members/stoneWindow/20.1.bmp" onload="javascript:if(this.width>500)this.style.width=500;"><BR><BR>Figure&nbsp;20.1:&nbsp;Customer&nbsp;Class&nbsp;<BR>Listing&nbsp;20.1:&nbsp;Customer&nbsp;Class&nbsp;<BR>
<DIV class=codeStyle>
<OL>
<LI><B><FONT color=#0000ff>class</FONT></B>&nbsp;Customer&nbsp;{&nbsp; 
<LI>&nbsp;&nbsp;<B><FONT color=#0000ff>public</FONT></B>&nbsp;<B><FONT color=#0000ff>static</FONT></B>&nbsp;<B><FONT color=#0000ff>final</FONT></B>&nbsp;<B><A href="http://www.javaresearch.org/source/jdk142/java/lang/String.java.html" target=_blank><FONT class=classLink color=#002c99><U>String</U></FONT></A></B>&nbsp;US&nbsp;=&nbsp;<FONT color=#ff33ff>"US"</FONT>;&nbsp; 
<LI>&nbsp;&nbsp;<B><FONT color=#0000ff>public</FONT></B>&nbsp;<B><FONT color=#0000ff>static</FONT></B>&nbsp;<B><FONT color=#0000ff>final</FONT></B>&nbsp;<B><A href="http://www.javaresearch.org/source/jdk142/java/lang/String.java.html" target=_blank><FONT class=classLink color=#002c99><U>String</U></FONT></A></B>&nbsp;CANADA&nbsp;=&nbsp;<FONT color=#ff33ff>"Canada"</FONT>;&nbsp; 
<LI>&nbsp;&nbsp;<B><FONT color=#0000ff>private</FONT></B>&nbsp;<B><A href="http://www.javaresearch.org/source/jdk142/java/lang/String.java.html" target=_blank><FONT class=classLink color=#002c99><U>String</U></FONT></A></B>&nbsp;address;&nbsp; 
<LI>&nbsp;&nbsp;<B><FONT color=#0000ff>private</FONT></B>&nbsp;<B><A href="http://www.javaresearch.org/source/jdk142/java/lang/String.java.html" target=_blank><FONT class=classLink color=#002c99><U>String</U></FONT></A></B>&nbsp;name;&nbsp; 
<LI>&nbsp;&nbsp;<B><FONT color=#0000ff>private</FONT></B>&nbsp;<B><A href="http://www.javaresearch.org/source/jdk142/java/lang/String.java.html" target=_blank><FONT class=classLink color=#002c99><U>String</U></FONT></A></B>&nbsp;zip,&nbsp;state,&nbsp;type;&nbsp; 
<LI>&nbsp;&nbsp;<B><FONT color=#0000ff>public</FONT></B>&nbsp;<B><FONT color=#0000ff>boolean</FONT></B>&nbsp;isValidAddress()&nbsp;{&nbsp; 
<LI>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;…&nbsp; 
<LI>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;…&nbsp; 
<LI>&nbsp;&nbsp;}&nbsp; 
<LI>&nbsp;&nbsp;<B><FONT color=#0000ff>public</FONT></B>&nbsp;Customer(<B><A href="http://www.javaresearch.org/source/jdk142/java/lang/String.java.html" target=_blank><FONT class=classLink color=#002c99><U>String</U></FONT></A></B>&nbsp;inp_name,&nbsp;<B><A href="http://www.javaresearch.org/source/jdk142/java/lang/String.java.html" target=_blank><FONT class=classLink color=#002c99><U>String</U></FONT></A></B>&nbsp;inp_address,&nbsp; 
<LI>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<B><A href="http://www.javaresearch.org/source/jdk142/java/lang/String.java.html" target=_blank><FONT class=classLink color=#002c99><U>String</U></FONT></A></B>&nbsp;inp_zip,&nbsp;<B><A href="http://www.javaresearch.org/source/jdk142/java/lang/String.java.html" target=_blank><FONT class=classLink color=#002c99><U>String</U></FONT></A></B>&nbsp;inp_state,&nbsp; 
<LI>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<B><A href="http://www.javaresearch.org/source/jdk142/java/lang/String.java.html" target=_blank><FONT class=classLink color=#002c99><U>String</U></FONT></A></B>&nbsp;inp_type)&nbsp;{&nbsp; 
<LI>&nbsp;&nbsp;&nbsp;&nbsp;name&nbsp;=&nbsp;inp_name;&nbsp; 
<LI>&nbsp;&nbsp;&nbsp;&nbsp;address&nbsp;=&nbsp;inp_address;&nbsp; 
<LI>&nbsp;&nbsp;&nbsp;&nbsp;zip&nbsp;=&nbsp;inp_zip;&nbsp; 
<LI>&nbsp;&nbsp;&nbsp;&nbsp;state&nbsp;=&nbsp;inp_state;&nbsp; 
<LI>&nbsp;&nbsp;&nbsp;&nbsp;type&nbsp;=&nbsp;inp_type;&nbsp; 
<LI>&nbsp;&nbsp;}&nbsp; 
<LI>}<I><FONT color=#339900>//end&nbsp;of&nbsp;class&nbsp;</FONT></I> </LI></OL></DIV><BR>&nbsp;&nbsp;&nbsp;&nbsp;不同的客户对象创建Customer对象并调用（invoke）isValidAddress方法验证客户地址的有效性。为了验证客户地址的有效性，Customer类期望利用一个地址验证类（address&nbsp;validator&nbsp;class），这个验证类提供了在接口AddressValidator中声明的接口。<BR>Listing&nbsp;20.2:&nbsp;AddressValidator&nbsp;as&nbsp;an&nbsp;Interface&nbsp;<BR>
<DIV class=codeStyle>
<OL>
<LI><B><FONT color=#0000ff>public</FONT></B>&nbsp;<B><FONT color=#0000ff>interface</FONT></B>&nbsp;AddressValidator&nbsp;{&nbsp; 
<LI>&nbsp;&nbsp;<B><FONT color=#0000ff>public</FONT></B>&nbsp;<B><FONT color=#0000ff>boolean</FONT></B>&nbsp;isValidAddress(<B><A href="http://www.javaresearch.org/source/jdk142/java/lang/String.java.html" target=_blank><FONT class=classLink color=#002c99><U>String</U></FONT></A></B>&nbsp;inp_address,&nbsp; 
<LI>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<B><A href="http://www.javaresearch.org/source/jdk142/java/lang/String.java.html" target=_blank><FONT class=classLink color=#002c99><U>String</U></FONT></A></B>&nbsp;inp_zip,&nbsp;<B><A href="http://www.javaresearch.org/source/jdk142/java/lang/String.java.html" target=_blank><FONT class=classLink color=#002c99><U>String</U></FONT></A></B>&nbsp;inp_state);&nbsp; 
<LI>}<I><FONT color=#339900>//end&nbsp;of&nbsp;class&nbsp;</FONT></I> </LI></OL></DIV><BR>&nbsp;&nbsp;&nbsp;让我们定义一个USAddress的验证类，来验证给定的U.S地址。<BR>Listing&nbsp;20.3:&nbsp;USAddress&nbsp;Class&nbsp;<BR>
<DIV class=codeStyle>
<OL>
<LI><B><FONT color=#0000ff>class</FONT></B>&nbsp;USAddress&nbsp;<B><FONT color=#0000ff>implements</FONT></B>&nbsp;AddressValidator&nbsp;{&nbsp; 
<LI>&nbsp;&nbsp;<B><FONT color=#0000ff>public</FONT></B>&nbsp;<B><FONT color=#0000ff>boolean</FONT></B>&nbsp;isValidAddress(<B><A href="http://www.javaresearch.org/source/jdk142/java/lang/String.java.html" target=_blank><FONT class=classLink color=#002c99><U>String</U></FONT></A></B>&nbsp;inp_address,&nbsp; 
<LI>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<B><A href="http://www.javaresearch.org/source/jdk142/java/lang/String.java.html" target=_blank><FONT class=classLink color=#002c99><U>String</U></FONT></A></B>&nbsp;inp_zip,&nbsp;<B><A href="http://www.javaresearch.org/source/jdk142/java/lang/String.java.html" target=_blank><FONT class=classLink color=#002c99><U>String</U></FONT></A></B>&nbsp;inp_state)&nbsp;{&nbsp; 
<LI>&nbsp;&nbsp;&nbsp;<B><FONT color=#0000ff>if</FONT></B>&nbsp;(inp_address.trim().<B><FONT color=#0000ff>length</FONT></B>()&nbsp;&lt;&nbsp;10)&nbsp; 
<LI>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<B><FONT color=#0000ff>return</FONT></B>&nbsp;<B><FONT color=#0000ff>false</FONT></B>;&nbsp; 
<LI>&nbsp;&nbsp;&nbsp;<B><FONT color=#0000ff>if</FONT></B>&nbsp;(inp_zip.trim().<B><FONT color=#0000ff>length</FONT></B>()&nbsp;&lt;&nbsp;5)&nbsp; 
<LI>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<B><FONT color=#0000ff>return</FONT></B>&nbsp;<B><FONT color=#0000ff>false</FONT></B>;&nbsp; 
<LI>&nbsp;&nbsp;&nbsp;<B><FONT color=#0000ff>if</FONT></B>&nbsp;(inp_zip.trim().<B><FONT color=#0000ff>length</FONT></B>()&nbsp;&gt;&nbsp;10)&nbsp; 
<LI>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<B><FONT color=#0000ff>return</FONT></B>&nbsp;<B><FONT color=#0000ff>false</FONT></B>;&nbsp; 
<LI>&nbsp;&nbsp;&nbsp;<B><FONT color=#0000ff>if</FONT></B>&nbsp;(inp_state.trim().<B><FONT color=#0000ff>length</FONT></B>()&nbsp;!=&nbsp;2)&nbsp; 
<LI>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<B><FONT color=#0000ff>return</FONT></B>&nbsp;<B><FONT color=#0000ff>false</FONT></B>;&nbsp; 
<LI>&nbsp;&nbsp;&nbsp;<B><FONT color=#0000ff>return</FONT></B>&nbsp;<B><FONT color=#0000ff>true</FONT></B>;&nbsp; 
<LI>&nbsp;&nbsp;}&nbsp; 
<LI>}<I><FONT color=#339900>//end&nbsp;of&nbsp;class&nbsp;</FONT></I> </LI></OL></DIV><BR>&nbsp;&nbsp;&nbsp;&nbsp;USAddress类实现AddressValidator接口，因此Customer对象使用USAddress实例作为验证客户地址过程的一部分是没有任何问题的。<BR>Listing&nbsp;20.4:&nbsp;Customer&nbsp;Class&nbsp;Using&nbsp;the&nbsp;USAddress&nbsp;Class&nbsp;<BR>
<DIV class=codeStyle>
<OL>
<LI><B><FONT color=#0000ff>class</FONT></B>&nbsp;Customer&nbsp;{&nbsp; 
<LI>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;…&nbsp; 
<LI>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;…&nbsp; 
<LI>&nbsp;<B><FONT color=#0000ff>public</FONT></B>&nbsp;<B><FONT color=#0000ff>boolean</FONT></B>&nbsp;isValidAddress()&nbsp;{&nbsp; 
<LI>&nbsp;&nbsp;&nbsp;<I><FONT color=#339900>//get&nbsp;an&nbsp;appropriate&nbsp;address&nbsp;validator&nbsp;</FONT></I> 
<LI>&nbsp;&nbsp;&nbsp;AddressValidator&nbsp;validator&nbsp;=&nbsp;getValidator(type);&nbsp; 
<LI>&nbsp;&nbsp;&nbsp;<I><FONT color=#339900>//Polymorphic&nbsp;call&nbsp;to&nbsp;validate&nbsp;the&nbsp;address&nbsp;</FONT></I> 
<LI>&nbsp;&nbsp;&nbsp;<B><FONT color=#0000ff>return</FONT></B>&nbsp;validator.isValidAddress(address,&nbsp;zip,&nbsp;state);&nbsp; 
<LI>&nbsp;}&nbsp; 
<LI>&nbsp;<B><FONT color=#0000ff>private</FONT></B>&nbsp;AddressValidator&nbsp;getValidator(<B><A href="http://www.javaresearch.org/source/jdk142/java/lang/String.java.html" target=_blank><FONT class=classLink color=#002c99><U>String</U></FONT></A></B>&nbsp;custType)&nbsp;{&nbsp; 
<LI>&nbsp;&nbsp;&nbsp;AddressValidator&nbsp;validator&nbsp;=&nbsp;<B><FONT color=#0000ff>null</FONT></B>;&nbsp; 
<LI>&nbsp;&nbsp;&nbsp;<B><FONT color=#0000ff>if</FONT></B>&nbsp;(custType.equals(Customer.US))&nbsp;{&nbsp; 
<LI>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;validator&nbsp;=&nbsp;<B><FONT color=#0000ff>new</FONT></B>&nbsp;USAddress();&nbsp; 
<LI>&nbsp;&nbsp;&nbsp;}&nbsp; 
<LI>&nbsp;&nbsp;&nbsp;<B><FONT color=#0000ff>return</FONT></B>&nbsp;validator;&nbsp; 
<LI>&nbsp;}&nbsp; 
<LI>}<I><FONT color=#339900>//end&nbsp;of&nbsp;class&nbsp;</FONT></I> </LI></OL></DIV>&nbsp;<BR><IMG style="CURSOR: pointer" onclick=javascript:window.open(this.src); src="http://www.javaresearch.org/members/stoneWindow/20.2.bmp" onload="javascript:if(this.width>500)this.style.width=500;"><BR>Figure&nbsp;20.2:&nbsp;Customer/USAddress&nbsp;Validator?Class&nbsp;Association&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;但是当验证来自加拿大的客户时，就要对应用进行改进。这需要一个验证加拿大客户地址的验证类。让我们假设已经存在一个用来验证加拿大客户地址的使用工具类CAAddress,。<BR>从下面的CAAdress类的实现，可以发现CAAdress提供了客户类Customer类所需要的验证服务。但是它所提供的接口不用于客户类Customer所期望的。<BR>Listing&nbsp;20.5:&nbsp;CAAdress&nbsp;Class&nbsp;with&nbsp;Incompatible&nbsp;Interface&nbsp;<BR>
<DIV class=codeStyle>
<OL>
<LI><B><FONT color=#0000ff>class</FONT></B>&nbsp;CAAddress&nbsp;{&nbsp; 
<LI>&nbsp;&nbsp;<B><FONT color=#0000ff>public</FONT></B>&nbsp;<B><FONT color=#0000ff>boolean</FONT></B>&nbsp;isValidCanadianAddr(<B><A href="http://www.javaresearch.org/source/jdk142/java/lang/String.java.html" target=_blank><FONT class=classLink color=#002c99><U>String</U></FONT></A></B>&nbsp;inp_address,&nbsp; 
<LI>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<B><A href="http://www.javaresearch.org/source/jdk142/java/lang/String.java.html" target=_blank><FONT class=classLink color=#002c99><U>String</U></FONT></A></B>&nbsp;inp_pcode,&nbsp;<B><A href="http://www.javaresearch.org/source/jdk142/java/lang/String.java.html" target=_blank><FONT class=classLink color=#002c99><U>String</U></FONT></A></B>&nbsp;inp_prvnc)&nbsp;{&nbsp; 
<LI>&nbsp;&nbsp;&nbsp;<B><FONT color=#0000ff>if</FONT></B>&nbsp;(inp_address.trim().<B><FONT color=#0000ff>length</FONT></B>()&nbsp;&lt;&nbsp;15)&nbsp; 
<LI>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<B><FONT color=#0000ff>return</FONT></B>&nbsp;<B><FONT color=#0000ff>false</FONT></B>;&nbsp; 
<LI>&nbsp;&nbsp;&nbsp;<B><FONT color=#0000ff>if</FONT></B>&nbsp;(inp_pcode.trim().<B><FONT color=#0000ff>length</FONT></B>()&nbsp;!=&nbsp;6)&nbsp; 
<LI>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<B><FONT color=#0000ff>return</FONT></B>&nbsp;<B><FONT color=#0000ff>false</FONT></B>;&nbsp; 
<LI>&nbsp;&nbsp;&nbsp;<B><FONT color=#0000ff>if</FONT></B>&nbsp;(inp_prvnc.trim().<B><FONT color=#0000ff>length</FONT></B>()&nbsp;&lt;&nbsp;6)&nbsp; 
<LI>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<B><FONT color=#0000ff>return</FONT></B>&nbsp;<B><FONT color=#0000ff>false</FONT></B>;&nbsp; 
<LI>&nbsp;&nbsp;&nbsp;<B><FONT color=#0000ff>return</FONT></B>&nbsp;<B><FONT color=#0000ff>true</FONT></B>;&nbsp; 
<LI>&nbsp;&nbsp;}&nbsp; 
<LI>}<I><FONT color=#339900>//end&nbsp;of&nbsp;class&nbsp;</FONT></I> </LI></OL></DIV><BR>&nbsp;&nbsp;&nbsp;&nbsp;CAAdress类提供了一个isValidCanadianAddr方法，但是Customer期望一个声明在AddressValidator接口中的isValidAddress方法。<BR>接口的不兼容使得Customer对象利用现有的CAAdress类是困难的。一种意见是改变CAAdress类的接口，但是可能会有其他的应用正在使用CAAdress类的这种形式。改变CAAdress类接口会影响现在使用CAAdress类的客户。<BR>应用适配器模式，类适配器CAAdressAdapter可以继承CAAdress类实现AddressValidator接口。<BR>&nbsp;<IMG style="CURSOR: pointer" onclick=javascript:window.open(this.src); src="http://www.javaresearch.org/members/stoneWindow/20.3.bmp" onload="javascript:if(this.width>500)this.style.width=500;"><BR>Figure&nbsp;20.3:&nbsp;Class&nbsp;Adapter&nbsp;for&nbsp;the&nbsp;CAAddress&nbsp;Class&nbsp;<BR>Listing&nbsp;20.6:&nbsp;CAAddressAdapter&nbsp;as&nbsp;a&nbsp;Class&nbsp;Adapter&nbsp;<BR>
<DIV class=codeStyle>
<OL>
<LI><B><FONT color=#0000ff>public</FONT></B>&nbsp;<B><FONT color=#0000ff>class</FONT></B>&nbsp;CAAddressAdapter&nbsp;<B><FONT color=#0000ff>extends</FONT></B>&nbsp;CAAddress&nbsp; 
<LI>&nbsp;&nbsp;<B><FONT color=#0000ff>implements</FONT></B>&nbsp;AddressValidator&nbsp;{&nbsp; 
<LI>&nbsp;&nbsp;<B><FONT color=#0000ff>public</FONT></B>&nbsp;<B><FONT color=#0000ff>boolean</FONT></B>&nbsp;isValidAddress(<B><A href="http://www.javaresearch.org/source/jdk142/java/lang/String.java.html" target=_blank><FONT class=classLink color=#002c99><U>String</U></FONT></A></B>&nbsp;inp_address,&nbsp; 
<LI>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<B><A href="http://www.javaresearch.org/source/jdk142/java/lang/String.java.html" target=_blank><FONT class=classLink color=#002c99><U>String</U></FONT></A></B>&nbsp;inp_zip,&nbsp;<B><A href="http://www.javaresearch.org/source/jdk142/java/lang/String.java.html" target=_blank><FONT class=classLink color=#002c99><U>String</U></FONT></A></B>&nbsp;inp_state)&nbsp;{&nbsp; 
<LI>&nbsp;&nbsp;&nbsp;&nbsp;<B><FONT color=#0000ff>return</FONT></B>&nbsp;isValidCanadianAddr(inp_address,&nbsp;inp_zip,&nbsp; 
<LI>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;inp_state);&nbsp; 
<LI>&nbsp;&nbsp;}&nbsp; 
<LI>}<I><FONT color=#339900>//end&nbsp;of&nbsp;class&nbsp;</FONT></I> </LI></OL></DIV><BR>&nbsp;&nbsp;&nbsp;&nbsp;因为适配器CAAdressAdapter实现了AddressValidator接口，客户端对象访问适配器CAAdressAdapter对象是没有任何问题的。当客户对象调用适配器实例的isValidAddress方法的时候，适配器在内部把调用传递给它继承的isValidCanadianAddr方法。<BR>在Customer类内部，getValidator私有方法需要扩展，以至于它可以在验证加拿大客户的时候返回一个CAAdressAdapter实例。返回的对象是多态的，USAddress和CAAddressAdapter都实现了AddressValidator接口，所以不用改变。<BR>Listing&nbsp;20.7:&nbsp;Customer&nbsp;Class&nbsp;Using&nbsp;the&nbsp;CAAddressAdapter&nbsp;Class&nbsp;<BR>
<DIV class=codeStyle>
<OL>
<LI><B><FONT color=#0000ff>class</FONT></B>&nbsp;Customer&nbsp;{&nbsp; 
<LI>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;…&nbsp; 
<LI>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;…&nbsp; 
<LI>&nbsp;&nbsp;<B><FONT color=#0000ff>public</FONT></B>&nbsp;<B><FONT color=#0000ff>boolean</FONT></B>&nbsp;isValidAddress()&nbsp;{&nbsp; 
<LI>&nbsp;&nbsp;&nbsp;&nbsp;<I><FONT color=#339900>//get&nbsp;an&nbsp;appropriate&nbsp;address&nbsp;validator&nbsp;</FONT></I> 
<LI>&nbsp;&nbsp;&nbsp;&nbsp;AddressValidator&nbsp;validator&nbsp;=&nbsp;getValidator(type);&nbsp; 
<LI>&nbsp;&nbsp;&nbsp;&nbsp;<I><FONT color=#339900>//Polymorphic&nbsp;call&nbsp;to&nbsp;validate&nbsp;the&nbsp;address&nbsp;</FONT></I> 
<LI>&nbsp;&nbsp;&nbsp;&nbsp;<B><FONT color=#0000ff>return</FONT></B>&nbsp;validator.isValidAddress(address,&nbsp;zip,&nbsp;state);&nbsp; 
<LI>&nbsp;&nbsp;}&nbsp; 
<LI>&nbsp;&nbsp;<B><FONT color=#0000ff>private</FONT></B>&nbsp;AddressValidator&nbsp;getValidator(<B><A href="http://www.javaresearch.org/source/jdk142/java/lang/String.java.html" target=_blank><FONT class=classLink color=#002c99><U>String</U></FONT></A></B>&nbsp;custType)&nbsp;{&nbsp; 
<LI>&nbsp;&nbsp;&nbsp;&nbsp;AddressValidator&nbsp;validator&nbsp;=&nbsp;<B><FONT color=#0000ff>null</FONT></B>;&nbsp; 
<LI>&nbsp;&nbsp;&nbsp;&nbsp;<B><FONT color=#0000ff>if</FONT></B>&nbsp;(custType.equals(Customer.US))&nbsp;{&nbsp; 
<LI>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;validator&nbsp;=&nbsp;<B><FONT color=#0000ff>new</FONT></B>&nbsp;USAddress();&nbsp; 
<LI>&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp; 
<LI>&nbsp;&nbsp;&nbsp;&nbsp;<B><FONT color=#0000ff>if</FONT></B>&nbsp;(type.equals(Customer.CANADA))&nbsp;{&nbsp; 
<LI>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;validator&nbsp;=&nbsp;<B><FONT color=#0000ff>new</FONT></B>&nbsp;CAAddressAdapter();&nbsp; 
<LI>&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp; 
<LI>&nbsp;&nbsp;&nbsp;&nbsp;<B><FONT color=#0000ff>return</FONT></B>&nbsp;validator;&nbsp; 
<LI>&nbsp;&nbsp;}&nbsp; 
<LI>}<I><FONT color=#339900>//end&nbsp;of&nbsp;class&nbsp;</FONT></I> </LI></OL></DIV><BR>&nbsp;&nbsp;&nbsp;&nbsp;CAAddressAdapter设计和对AddressValidator（声明期望的接口）对象的多态调用使Customer可以利用接口不兼容CAAddress类提供的服务。<BR>The&nbsp;class&nbsp;diagram&nbsp;in&nbsp;Figure&nbsp;20.4&nbsp;shows&nbsp;the&nbsp;overall&nbsp;class&nbsp;association.<BR>&nbsp;<IMG style="CURSOR: pointer" onclick=javascript:window.open(this.src); src="http://www.javaresearch.org/members/stoneWindow/20.4.bmp" onload="javascript:if(this.width>500)this.style.width=500;"><BR>Figure&nbsp;20.4:&nbsp;Address&nbsp;Validation&nbsp;Application?Using&nbsp;Class&nbsp;Adapter&nbsp;<BR>The&nbsp;sequence&nbsp;diagram&nbsp;in&nbsp;Figure&nbsp;20.5&nbsp;depicts&nbsp;the&nbsp;message&nbsp;flow&nbsp;when&nbsp;the&nbsp;CAAddressAdapter&nbsp;is&nbsp;designed&nbsp;as&nbsp;a&nbsp;class&nbsp;adapter.<BR>&nbsp;<IMG style="CURSOR: pointer" onclick=javascript:window.open(this.src); src="http://www.javaresearch.org/members/stoneWindow/20.5.bmp" onload="javascript:if(this.width>500)this.style.width=500;"><BR>Figure&nbsp;20.5:&nbsp;Address&nbsp;Validation&nbsp;Message&nbsp;Flow?Using&nbsp;Class&nbsp;Adapter&nbsp;<BR>作为对象适配器的地址适配器<BR>当讨论以类适配器来实现地址适配器时，我们说客户类期望的AddressValidator接口是Java接口形式。现在，让我们假设客户类期望AddressValidator接口是抽象类而不是java接口。因为适配器CAAdapter必须提供抽象类AddressValidatro中声明的接口，适配器必须是AddressValidator抽象类的子类、实现抽象方法。<BR>
<DIV class=codeStyle>
<OL>
<LI>Listing&nbsp;20.8:&nbsp;AddressValidator&nbsp;as&nbsp;an&nbsp;Abstract&nbsp;<B><A href="http://www.javaresearch.org/source/jdk142/java/lang/Class.java.html" target=_blank><FONT class=classLink color=#002c99><U>Class</U></FONT></A></B>&nbsp; 
<LI><B><FONT color=#0000ff>public</FONT></B>&nbsp;<B><FONT color=#0000ff>abstract</FONT></B>&nbsp;<B><FONT color=#0000ff>class</FONT></B>&nbsp;AddressValidator&nbsp;{&nbsp; 
<LI>&nbsp;&nbsp;<B><FONT color=#0000ff>public</FONT></B>&nbsp;<B><FONT color=#0000ff>abstract</FONT></B>&nbsp;<B><FONT color=#0000ff>boolean</FONT></B>&nbsp;isValidAddress(<B><A href="http://www.javaresearch.org/source/jdk142/java/lang/String.java.html" target=_blank><FONT class=classLink color=#002c99><U>String</U></FONT></A></B>&nbsp;inp_address,&nbsp; 
<LI>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<B><A href="http://www.javaresearch.org/source/jdk142/java/lang/String.java.html" target=_blank><FONT class=classLink color=#002c99><U>String</U></FONT></A></B>&nbsp;inp_zip,&nbsp;<B><A href="http://www.javaresearch.org/source/jdk142/java/lang/String.java.html" target=_blank><FONT class=classLink color=#002c99><U>String</U></FONT></A></B>&nbsp;inp_state);&nbsp; 
<LI>}<I><FONT color=#339900>//end&nbsp;of&nbsp;class&nbsp;</FONT></I> 
<LI>Listing&nbsp;20.9:&nbsp;CAAddressAdapter&nbsp;<B><A href="http://www.javaresearch.org/source/jdk142/java/lang/Class.java.html" target=_blank><FONT class=classLink color=#002c99><U>Class</U></FONT></A></B>&nbsp; 
<LI><B><FONT color=#0000ff>class</FONT></B>&nbsp;CAAddressAdapter&nbsp;<B><FONT color=#0000ff>extends</FONT></B>&nbsp;AddressValidator&nbsp;{&nbsp; 
<LI>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;…&nbsp; 
<LI>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;…&nbsp; 
<LI>&nbsp;&nbsp;<B><FONT color=#0000ff>public</FONT></B>&nbsp;CAAddressAdapter(CAAddress&nbsp;address)&nbsp;{&nbsp; 
<LI>&nbsp;&nbsp;&nbsp;&nbsp;objCAAddress&nbsp;=&nbsp;address;&nbsp; 
<LI>&nbsp;&nbsp;}&nbsp; 
<LI>&nbsp;&nbsp;<B><FONT color=#0000ff>public</FONT></B>&nbsp;<B><FONT color=#0000ff>boolean</FONT></B>&nbsp;isValidAddress(<B><A href="http://www.javaresearch.org/source/jdk142/java/lang/String.java.html" target=_blank><FONT class=classLink color=#002c99><U>String</U></FONT></A></B>&nbsp;inp_address,&nbsp; 
<LI>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<B><A href="http://www.javaresearch.org/source/jdk142/java/lang/String.java.html" target=_blank><FONT class=classLink color=#002c99><U>String</U></FONT></A></B>&nbsp;inp_zip,&nbsp;<B><A href="http://www.javaresearch.org/source/jdk142/java/lang/String.java.html" target=_blank><FONT class=classLink color=#002c99><U>String</U></FONT></A></B>&nbsp;inp_state)&nbsp;{&nbsp; 
<LI>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;…&nbsp; 
<LI>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;…&nbsp; 
<LI>&nbsp;&nbsp;}&nbsp; 
<LI>}<I><FONT color=#339900>//end&nbsp;of&nbsp;class&nbsp;</FONT></I> </LI></OL></DIV><BR>&nbsp;&nbsp;&nbsp;&nbsp;因为多继承在JAVA中不支持，现在适配器CAAddressAdapter不能继承现有的CAAddress类，它已经使用了唯一一次继承其他类的机会。<BR>应用对象适配器模式，CAAddressAdapter可以包含一个适配者CAAddress的一个实例。当适配器第一次创建的时候，这个适配者的实例通过客户端传递给适配器。通常，适配者实例可以通过下面两种方式提供给包装它的适配器。<BR>（1）&nbsp;&nbsp;&nbsp;&nbsp;对象适配器的客户端可以传递一个适配者的实例给适配器。这种方式在选择类的形式上有很大的灵活性，但是客户端感知了适配者或者适配过程。这种方法在适配器不但需要适配者对象行为而且需要特定状态时很适合。<BR>（2）&nbsp;&nbsp;&nbsp;&nbsp;适配器可以自己创建适配者实例。这种方法相对来说缺乏灵活性。适用于适配器只需要适配者对象的行为而不需要适配者对象的特定状态的情况。<BR>&nbsp;<IMG style="CURSOR: pointer" onclick=javascript:window.open(this.src); src="http://www.javaresearch.org/members/stoneWindow/20.6.bmp" onload="javascript:if(this.width>500)this.style.width=500;"><BR>Figure&nbsp;20.6:&nbsp;Object&nbsp;Adapter&nbsp;for&nbsp;the&nbsp;CAAddress&nbsp;Class&nbsp;<BR>Listing&nbsp;20.10:&nbsp;CAAddressAdapter&nbsp;as&nbsp;an&nbsp;Object&nbsp;Adapter&nbsp;<BR>
<DIV class=codeStyle>
<OL>
<LI><B><FONT color=#0000ff>class</FONT></B>&nbsp;CAAddressAdapter&nbsp;<B><FONT color=#0000ff>extends</FONT></B>&nbsp;AddressValidator&nbsp;{&nbsp; 
<LI>&nbsp;&nbsp;<B><FONT color=#0000ff>private</FONT></B>&nbsp;CAAddress&nbsp;objCAAddress;&nbsp; 
<LI>&nbsp;&nbsp;<B><FONT color=#0000ff>public</FONT></B>&nbsp;CAAddressAdapter(CAAddress&nbsp;address)&nbsp;{&nbsp; 
<LI>&nbsp;&nbsp;&nbsp;&nbsp;objCAAddress&nbsp;=&nbsp;address;&nbsp; 
<LI>&nbsp;&nbsp;}&nbsp; 
<LI>&nbsp;&nbsp;<B><FONT color=#0000ff>public</FONT></B>&nbsp;<B><FONT color=#0000ff>boolean</FONT></B>&nbsp;isValidAddress(<B><A href="http://www.javaresearch.org/source/jdk142/java/lang/String.java.html" target=_blank><FONT class=classLink color=#002c99><U>String</U></FONT></A></B>&nbsp;inp_address,&nbsp; 
<LI>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<B><A href="http://www.javaresearch.org/source/jdk142/java/lang/String.java.html" target=_blank><FONT class=classLink color=#002c99><U>String</U></FONT></A></B>&nbsp;inp_zip,&nbsp;<B><A href="http://www.javaresearch.org/source/jdk142/java/lang/String.java.html" target=_blank><FONT class=classLink color=#002c99><U>String</U></FONT></A></B>&nbsp;inp_state)&nbsp;{&nbsp; 
<LI>&nbsp;&nbsp;&nbsp;&nbsp;<B><FONT color=#0000ff>return</FONT></B>&nbsp;objCAAddress.isValidCanadianAddr(inp_address,&nbsp; 
<LI>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;inp_zip,&nbsp;inp_state);&nbsp; 
<LI>&nbsp;&nbsp;}&nbsp; 
<LI>}<I><FONT color=#339900>//end&nbsp;of&nbsp;class&nbsp;</FONT></I> </LI></OL></DIV><BR>&nbsp;&nbsp;&nbsp;&nbsp;当客户对象调用CAAddressAdapter（adapter）上的isValidAddress方法时,&nbsp;适配器在内部调用CAAddress(adaptee)上的isValidCanadianAddr方法。<BR>The&nbsp;class&nbsp;diagram&nbsp;in&nbsp;Figure&nbsp;20.7&nbsp;shows&nbsp;the&nbsp;overall&nbsp;class&nbsp;association&nbsp;when&nbsp;the&nbsp;address&nbsp;adapter&nbsp;is&nbsp;designed&nbsp;as&nbsp;an&nbsp;object&nbsp;adapter.<BR>&nbsp;<IMG style="CURSOR: pointer" onclick=javascript:window.open(this.src); src="http://www.javaresearch.org/members/stoneWindow/20.7.bmp" onload="javascript:if(this.width>500)this.style.width=500;"><BR>Figure&nbsp;20.7:&nbsp;Address&nbsp;Validation&nbsp;Application?Using&nbsp;Object&nbsp;Adapter&nbsp;<BR>从这个例子可以看出，适配器可以使Customer（client）类访问借口不兼容的CAAddress(adaptee)所提供的服务！<BR>The&nbsp;sequence&nbsp;diagram&nbsp;in&nbsp;Figure&nbsp;20.8&nbsp;shows&nbsp;the&nbsp;message&nbsp;flow&nbsp;when&nbsp;the&nbsp;adapter&nbsp;CAAddressAdapter&nbsp;is&nbsp;designed&nbsp;as&nbsp;an&nbsp;object&nbsp;adapter.&nbsp;<BR>&nbsp;<IMG style="CURSOR: pointer" onclick=javascript:window.open(this.src); src="http://www.javaresearch.org/members/stoneWindow/20.8.bmp" onload="javascript:if(this.width>500)this.style.width=500;"><BR>Figure&nbsp;20.8:&nbsp;Address&nbsp;Validation&nbsp;Message&nbsp;Flow?Using&nbsp;Object&nbsp;Adapter&nbsp;<BR>附件为原文和代码：<BR>[img]<A class=l2 href="http://www.javaresearch.org/members/stoneWindow/24.rar" target=_blank><FONT color=#002c99>附件：24.rar(17K)</FONT></A>&nbsp;<A class=l2 href="http://www.javaresearch.org/members/stoneWindow/Chapter_20.doc" target=_blank><FONT color=#002c99>附件：Chapter_20.doc(267K)</FONT></A>&nbsp;<img src ="http://www.blogjava.net/mlh123caoer/aggbug/30901.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/mlh123caoer/" target="_blank">草儿</a> 2006-02-16 09:06 <a href="http://www.blogjava.net/mlh123caoer/archive/2006/02/16/30901.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>享元（Flyweight）模式</title><link>http://www.blogjava.net/mlh123caoer/archive/2006/02/16/30900.html</link><dc:creator>草儿</dc:creator><author>草儿</author><pubDate>Thu, 16 Feb 2006 01:04:00 GMT</pubDate><guid>http://www.blogjava.net/mlh123caoer/archive/2006/02/16/30900.html</guid><wfw:comment>http://www.blogjava.net/mlh123caoer/comments/30900.html</wfw:comment><comments>http://www.blogjava.net/mlh123caoer/archive/2006/02/16/30900.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.blogjava.net/mlh123caoer/comments/commentRss/30900.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/mlh123caoer/services/trackbacks/30900.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 一、&nbsp;享元（Flyweight）模式(转贴）Flyweight在拳击比赛中指最轻量级，即"蝇量级"，有些作者翻译为"羽量级"。这里使用"享元模式"更能反映模式的用意。享元模式以共享的方式高效地支持大量的细粒度对象。享元对象能做到共享的关键是区分内蕴状态（Internal State）和外蕴状态（External State）。内蕴状态是存储在享元对象内部并且不会随环境改变而改变。...&nbsp;&nbsp;<a href='http://www.blogjava.net/mlh123caoer/archive/2006/02/16/30900.html'>阅读全文</a><img src ="http://www.blogjava.net/mlh123caoer/aggbug/30900.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/mlh123caoer/" target="_blank">草儿</a> 2006-02-16 09:04 <a href="http://www.blogjava.net/mlh123caoer/archive/2006/02/16/30900.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>