📄 7classpatterns.html
字号:
<html>
<head>
<meta http-equiv="content-type" content="text/html;charset=iso-8859-1">
<title>Together Tutorial -- Part 7</title>
<link rel="stylesheet" href="tutor.css" type="text/css">
</head>
<body bgcolor="white" link="#003399" alink="#999999" vlink="#000066">
<div align="left">
<p class="head2"><span style="font-size: 9pt">
<a href="mailto:%20e.w@263.net">翻译: 李颖(e.w@263.net)</a></span></p>
</div>
<div align="center">
<p class="head2"><a name="top"></a>Together 教程<br>
7: 使用类模式进行代码重构</p>
</div>
<p>在前面的课程中, 我们讨论了模板模式. 现在我们来考虑一下更复杂的模块模式. 我们主要讨论抽象工厂模式(Abstract Factory pattern),
它是 Together 附带的 GoF 模式的一部分.</p>
<p>Together 中的模式对于自动创建哪些难于用手工书写的代码是非常有用的. 而且它们对于重新组织和构造代码也是非常主要的.
这也就是这一课中你将要使用模式的方式. 但是, 我们首先要进行一些未完成的工作, 对我们唯一的业务规则编写代码.</p>
<p><b>目录:</b></p>
<ul>
<li><a class="onPage" href="#coding">编写业务规则代码</a><li><a class="onPage" href="#refactor">
使用 GoF 模式重构代码</a><li><a class="onPage" href="#finish">对模型图和代码进行最后的修正</a><li><a class="onPage" href="#tip">
技巧</a></ul>
<p>GoF 是 "Gang of Four" 的缩写. 它的意思是: Eric Gamma, Richard Helm, Ralph Johnson,
和 John Vlissides 四人, 他们是著名的《<i>Design Patterns</i>》和《<i>Elements of
Reusable Object-Oriented Software</i>》的作者.</p>
<p></p>
<p><img height="2" width="900" src="images/generic/rainbow2.gif" alt="Divider line"></p>
<p class="head3"><a name="coding"></a>编写业务规则代码</p>
<p>让我们来编写一些简单的代码, 以便从 <b>Flight.makeReservation()</b> 生成一个时序图.
我们前面的对活动图的讨论中包含了描述代码的业务规则:</p>
<dl>
<dd><b>如果售出的机票数不超过该航班容量, 那么你可以预定航班.</b> </dd>
</dl>
<p><img src="images/airline/addiagramcomplete.png" width="623" height="430" border="0" alt="Activity diagram" hspace="10" vspace="10"></p>
<p>下面是我们的 <b>Flight.makeReservation()</b> 方法代码.</p>
<p></p>
<table border="0" cellpadding="0" cellspacing="1" bgcolor="#CCCCCC">
<tr>
<td bgcolor="#CCCCCC">
<table border="0" cellpadding="5" cellspacing="2">
<tr>
<td valign="top" bgcolor="white">
<pre><tt>public void makeReservation(String name, int tKind) throws ReservationException {
int t = this.numberOfTickets();
int c = lnkFlightDescription.getCapacity();
<font color="#336600">// Make a reservation only if the number of tickets sold is less than the plane capacity</font>
if (t < c) {
Reservation r = new Reservation(nam,tKind);
lnkReservation.add(r);
}
else throw new ReservationException();
}</pre>
</td>
</tr>
</table>
</td>
</tr>
</table>
<p></p>
<table border="0" cellpadding="0" cellspacing="2" bgcolor="#993300" width="100%">
<tr>
<td bgcolor="#993300">
<table border="0" cellpadding="0" cellspacing="2" bgcolor="#ffffcc" width="100%">
<tr>
<td bgcolor="#ffffcc"><b>操作步骤:</b> 完成你的 <b>Flight.makeReservation()</b>
方法代码.</td>
</tr>
</table>
</td>
</tr>
</table>
<p></p>
<table border="0" cellpadding="0" cellspacing="1" bgcolor="#CCCCCC">
<tr>
<td bgcolor="#CCCCCC">
<table border="0" cellpadding="5" cellspacing="2">
<tr>
<td valign="top" bgcolor="white">
<p>你可以将上面的代码复制到 Together 中. 不过, 不过你手工输入这些代码,
你可能会看到编辑器的<i>代码感应</i>效果. </p>
<p>右图显示了表达式 <b>lnkFlightDescription</b> 的代码感应效果.
当我们输入 "." 时, 编辑器显示 <b>FlightDescription</b>
的方法列表. 我们简单地点击方法名即可将方法插入到代码中.</p>
</td>
<td valign="top" bgcolor="white">
<p><img src="images/airline/pro7_codesense.png" width="456" height="264" border="0" alt="Code completion"></p>
</td>
</tr>
</table>
</td>
</tr>
</table>
<p></p>
<p> <b>Reservation</b> 构造方法还只是一个空方法. 让我们来使用它地两个参数: <b>name</b> 和 <b>tKind</b>. <b>name</b>
参数很简单. 但 <b>tKind</b> 参数需要考虑一下. 现在只需要简单地按以下方法进行:</p>
<dl>
<dd><b>如果 tKind 为 1, 创建一个 Coach 类的机票. 如果 tKind 为 2, 创建一个 FirstClass
类的机票. 否则, 不创建机票.</b>
</dl>
<table border="0" cellpadding="0" cellspacing="2" bgcolor="#993300" width="100%">
<tr>
<td bgcolor="#993300">
<table border="0" cellpadding="0" cellspacing="2" bgcolor="#ffffcc" width="100%">
<tr>
<td bgcolor="#ffffcc"><b>操作步骤:</b> 为 <b>Reservation</b>
构造方法填写代码.</td>
</tr>
</table>
</td>
</tr>
</table>
<p>下面是我们的 <b>Reservation</b> 构造方法代码.</p>
<table border="0" cellpadding="0" cellspacing="1" bgcolor="#CCCCCC">
<tr>
<td bgcolor="#CCCCCC">
<table border="0" cellpadding="5" cellspacing="2">
<tr>
<td valign="top" bgcolor="white">
<pre>public Reservation(String name, int tKind) {
this.name = name;
<font color="#336600">// We will refactor this next piece of code</font>
lnkTicket = null;
if (tKind ==<font color="#ee0000"> 1</font>)
lnkTicket = new Coach() ;
else if (tKind ==<font color="#ee0000"> 2</font>)
lnkTicket = new FirstClass();
}</pre>
</td>
</tr>
</table>
</td>
</tr>
</table>
<p></p>
<hr>
<p class="head3"><a name="refactor"></a>使用 GoF 模式重构代码</p>
<p>现在航空公司工程需要进行大的扩展了. 确定机票类型的代码目前完全在 <b>Reservation</b> 构造方法中实现.
一种很自然的改进方案是将创建机票的代码移动到一个新的对象中: 一个创建机票的类工厂对象.</p>
<p>在这一课中, 你将建立一个 <b>TicketMaster</b> 类用来创建实际的 <b>Ticket</b> 类. GoF
模式集合中的抽象工厂模式将完成这种困难的工作.</p>
<table border="0" cellpadding="0" cellspacing="2" bgcolor="#993300" width="100%">
<tr>
<td bgcolor="#993300">
<table border="0" cellpadding="0" cellspacing="2" bgcolor="#ffffcc" width="100%">
<tr>
<td bgcolor="#ffffcc"><b>操作步骤:</b> 应用 GoF
模式集合中的抽象工厂模式. 名为 <b>Abstract Factory</b>, <b>Concrete Factory</b>,
以及 <b>Abstract Product</b>, 如下:<ul>
<li><b>ICreateTickets</b> 接口应用 <b>Abstract Factory</b>
模式<li><b>Ticket</b> 类应用 <b>Abstract Product</b>
模式<li><b>TicketMaster</b> 类应用 <b>Concrete Factory</b>
模式</ul>
<p></p>
</td>
</tr>
</table>
</td>
</tr>
</table>
<p></p>
<p>选择 Designer 工具条中的<b>使用模式创建类</b>按钮(<img src="images/icons/classbypatternicon.png" width="15" height="16" border="0" align="top" hspace="1" alt="Class by pattern icon">)然后点击
Designer 面板. 此时将出现一个模式选择对话框, 它的左侧是一个模式选择面板. 展开 GoF 文件夹可以看到 11 个模式选项. Abstract Factory
是 GoF 模式列表中的第一个.</p>
<table border="0" cellpadding="0" cellspacing="1" bgcolor="#CCCCCC">
<tr>
<td bgcolor="#CCCCCC">
<table border="0" cellpadding="5" cellspacing="2">
<tr>
<td valign="top" bgcolor="white">
<p>在对话框的右上面板中输入使用模式的类的名称. 你必须直接输入 <b>ICreateTickets</b>
和 <b>TicketMaster</b>, 因为它们还不存在.</p>
<p>不要输入 <b>Ticket</b>, 我们使用 <b>Abstract product</b>
文本框右侧的选择框(<img src="images/icons/selectboxbutton.gif" width="21" height="21" border="0" align="top" alt="Select button" hspace="1">)来选择这个类.</p>
<p></p>
</td>
<td valign="top" bgcolor="white"><img src="images/airline/pro7_newabstractfactory.png" width="449" height="358" border="0" alt="Pick abstract factory" hspace="3"></td>
</tr>
</table>
</td>
</tr>
</table>
<p></p>
<table border="0" cellpadding="0" cellspacing="2" bgcolor="#993300" width="100%">
<tr>
<td bgcolor="#993300">
<table border="0" cellpadding="0" cellspacing="2" bgcolor="#ffffcc" width="100%">
<tr>
<td bgcolor="#ffffcc"><b>操作步骤:</b> 将 <b>Product</b>
分配为 <b>Ticket</b> 类并完成模式的创建.</td>
</tr>
</table>
</td>
</tr>
</table>
<p></p>
<table border="0" cellpadding="0" cellspacing="1" bgcolor="#CCCCCC">
<tr>
<td bgcolor="#CCCCCC">
<table border="0" cellpadding="5" cellspacing="2">
<tr>
<td valign="top" bgcolor="white">首先点击模式选择对话框底部的 Next
按钮.
<p><img src="images/airline/hitnextbutton.gif" width="84" height="32" border="0" alt="Next button" hspace="5"></p>
<p>下一个模式窗口包括一个文本框用于输入 product. 点击其中的选择框将出现类选择窗口,
类似下图所示.</p>
<p>要选择 product, 首先展开 <b>Model</b>, 然后展开 <b>AirlinePD</b>.
然后选择 <b>Ticket</b> 类, 并点击 OK 按钮.</p>
</td>
</tr>
<tr>
<td valign="top" bgcolor="white"><img src="images/airline/abstractfactoryfinish.png" width="653" height="425" border="0" alt="Choose product dialog box" hspace="10" vspace="5"></td>
</tr>
<tr>
<td valign="top" bgcolor="white">
<p>点击 Finish 按钮完成模式创建工作.</p>
</td>
</tr>
</table>
</td>
</tr>
</table>
<p></p>
<hr>
<p class="head3"><a name="finish"></a>对模型和代码进行最后的修正</p>
<p>创建一个模式可能使得模型图变得比较混乱, 如果这个过程中产生了新的类或者接口尤其如此. 你的模型图现在包括几个新的依赖以及 <b>TicketMaster</b>
类和 <b>ICreateTickets</b> 接口. </p>
<table border="0" cellpadding="0" cellspacing="2" bgcolor="#993300" width="100%">
<tr>
<td bgcolor="#993300">
<table border="0" cellpadding="0" cellspacing="2" bgcolor="#ffffcc" width="100%">
<tr>
<td bgcolor="#ffffcc"><b>操作步骤:</b> 重新排列 <b>AirlinePD</b>
模型图以便显示整个模型.</td>
</tr>
</table>
</td>
</tr>
</table>
<p>这一步很简单. 打开模型图的右键菜单并选择 <b>Layout | All</b>.</p>
<table border="0" cellpadding="0" cellspacing="1" bgcolor="#CCCCCC">
<tr>
<td bgcolor="#CCCCCC">
<table border="0" cellpadding="5" cellspacing="2">
<tr>
<td valign="top" bgcolor="white">
<p>下图是 <b>Explorer</b> 面板的 Overview 页. 右图是对应的 <b>Designer</b>
面板. (我们的连接显示为矩形线.)</p>
<p><img src="images/airline/pro7_overview.png" width="200" height="200" border="0" hspace="5" alt="Overview" vspace="5"></p>
</td>
<td valign="top" bgcolor="white">
<p><img src="images/airline/pro7_abstractfactorydiagram.png" width="542" height="250" border="0" hspace="5"></p>
</td>
</tr>
</table>
</td>
</tr>
</table>
<p></p>
<p>此时代码已经基本完成了, 但还没完全完成. 记住我们最初的目标: 重构代码, 将创建 <b>Ticket</b> 类的代码从 <b>Reservation</b>
类移动到 <b>TicketMaster</b> 中. 下面是下一个任务的描述.</p>
<table border="0" cellpadding="0" cellspacing="2" bgcolor="#993300" width="100%">
<tr>
<td bgcolor="#993300">
<table border="0" cellpadding="0" cellspacing="2" bgcolor="#ffffcc" width="100%">
<tr>
<td bgcolor="#ffffcc"><b>操作步骤:</b> 修改 <b>ICreateTickets</b>
的操作, 接受一个 <b>int</b> 类型参数; 在 <b>TicketMaster</b>
类中进行对应的修改.</td>
</tr>
</table>
</td>
</tr>
</table>
<p>这是两个简单的小步骤:</p>
<ol>
<li>使用内嵌编辑器修改 <b>ICreateTickets</b> 中的操作, 如下:<br>
<br>
<b><i>createTicket(tKind:int):Ticket<br>
<br>
</i></b>
<li>按 <Ctrl> 键并将操作从 <b>ICreateTickets</b> 拖动到 <b>TicketMaster</b>.
删除原来的无参数的 <b>TicketMaster.createTicket()</b> 方法. </ol>
<table border="0" cellpadding="0" cellspacing="2" bgcolor="#993300" width="100%">
<tr>
<td bgcolor="#993300">
<table border="0" cellpadding="0" cellspacing="2" bgcolor="#ffffcc" width="100%">
<tr>
<td bgcolor="#ffffcc"><b>操作步骤:</b> 将 <b>Ticket</b>
的创建代码从 <b>Reservation</b> 移动到 <b>TicketMaster</b>
并修正语法错误.</td>
</tr>
</table>
</td>
</tr>
</table>
<p>你可以在 <b>Editor</b> 面板中通过剪切和复制来移动代码. 但是移动后的代码不能立即编译. 你需要进行两个小修改 --
在方法开始处声明一个 <b>Ticket</b> 类型变量并在结束处返回它.</p>
<p>我们将 <b>Ticket</b> 类型变量改名为 <b>t</b> (原来是 <b>lnkTicket</b>), 如下所示.</p>
<table border="0" cellpadding="0" cellspacing="1" bgcolor="#CCCCCC">
<tr>
<td bgcolor="#CCCCCC">
<table border="0" cellpadding="5" cellspacing="2">
<tr>
<td valign="top" bgcolor="white">
<pre>public Ticket createTicket(int tKind) {
Ticket t = null;
if (tKind ==<font color="#ee0000"> 1</font>)
t = new Coach() ;
else if (tKind ==<font color="#ee0000"> 2</font>)
t = new FirstClass();
return t;
}</pre>
</td>
</tr>
</table>
</td>
</tr>
</table>
<p>对意义重大的常量 1 和 2 进行文档描述是个很好的主意(或者更好的方案是完全消除它们). 但是我们把这个决策留给你决定.</p>
<table border="0" cellpadding="0" cellspacing="2" bgcolor="#993300" width="100%">
<tr>
<td bgcolor="#993300">
<table border="0" cellpadding="0" cellspacing="2" bgcolor="#ffffcc" width="100%">
<tr>
<td bgcolor="#ffffcc"><b>操作步骤:</b> 完成 <b>Reservation</b>
构造方法, 使它通过一个 <b>TicketMaster</b> 创建适当类型的 <b>Ticket</b>.</td>
</tr>
</table>
</td>
</tr>
</table>
<p>下面是我们的新代码, 改造后的 <b>Reservation</b> 构造方法.</p>
<table border="0" cellpadding="0" cellspacing="1" bgcolor="#CCCCCC">
<tr>
<td bgcolor="#CCCCCC">
<table border="0" cellpadding="5" cellspacing="2">
<tr>
<td valign="top" bgcolor="white">
<pre>public Reservation(String name, int tKind) {
this.name = name;
TicketMaster tm = new TicketMaster();
lnkTicket = tm.createTicket(tKind);
}</pre>
</td>
</tr>
</table>
</td>
</tr>
</table>
<p></p>
<table border="0" cellpadding="0" cellspacing="2" bgcolor="#993300" width="100%">
<tr>
<td bgcolor="#993300">
<table border="0" cellpadding="0" cellspacing="2" bgcolor="#ffffcc" width="100%">
<tr>
<td bgcolor="#ffffcc"><b>操作步骤:</b> 编译代码以便检查工作结果.
修正所有的语法错误. (如果有语法错误的话, 应该是比较小的错误.)</td>
</tr>
</table>
</td>
</tr>
</table>
<p></p>
<table border="0" cellpadding="0" cellspacing="1" bgcolor="#CCCCCC">
<tr>
<td bgcolor="#CCCCCC">
<table border="0" cellpadding="5" cellspacing="2">
<tr>
<td valign="top" bgcolor="white">
<p>Make 和 Build 命令在主菜单中的 <b>Project</b> 下,
也在主工具条中. 你也可以在 Message 面板的 Builder 页中找到这些命令.
编译的输出结果显示在 Message 面板中.</p>
<p>如果你的代码有错误, 点击错误信息可在编辑器中将错误的代码高亮显示.
继续本课程前请确保修正了你的代码中的错误.</p>
</td>
<td valign="top" bgcolor="white">
<p><img src="images/airline/compilebuttons.png" width="95" height="40" border="0" alt="Compile buttons" hspace="5" vspace="5"></p>
</td>
</tr>
</table>
</td>
</tr>
</table>
<p></p>
<hr>
<p class="head3"><a name="tip"></a>技巧</p>
<ul>
<li>对于这个工程还有还有其他适用的 GoF 模式. 例如, Composite 模式是一种简单的方法,
可用来支持团体或个人预定航班.<li>可以在 Designer 面板种同时选择多个类, 方法是点击鼠标左键并画一个矩形接触到这些类.
当它们被选中后, 你可以成组的移动他们. <li>按 <Ctrl> 键并拖动操作操作,
可将操作从抽象类或接口中复制到实体类. Together 将使复制的操作成为实体方法.
<li>使用 Designer 面板可以在编辑器中浏览代码. 例如, 如果你希望将语句从一个方法复制到另一个方法, 首先在
Designer 中点击方法浏览源代码. 然后复制代码. 然后通过 Designer 浏览到目标方法并复制即可. </ul>
<p>
<div align="center">
<hr>
<img height="19" width="297" src="images/generic/nvbuttons.gif" vspace="10" alt="Navigation bar" usemap="#nvbuttonsb601029d" border="0"><map name="nvbuttonsb601029d"><area href="#top" coords="101,2,146,17" shape="rect"><area href="6patterns.html" coords="0,2,96,16" shape="rect"><area href="8sequencediagrams.html" coords="152,1,208,17" shape="rect"><area href="index.html" coords="216,1,295,17" shape="rect"></map>
<hr>
</div>
<div align="left">
<p class="footnote">Copyright © 2002 TogetherSoft Corporation. All rights reserved.</p>
</div>
<p class="footnote"><font color="#666666">Last Revised: </font><csobj w="88" h="12" t="DateTime" format="MedDate" region="0">Fri, Mar 8, 2002</csobj>
<p class="footnote"><span style="font-size: 9pt">
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -