1 Wicket实现
Wicket模板是html格式,示例:index.html
Html代码
- <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
- <html>
- <head>
- <title>Index.html</title>
-
- <meta http-equiv="keywords" content="keyword1,keyword2,keyword3">
- <meta http-equiv="description" content="this is my page">
- <meta http-equiv="content-type" content="text/html; charset=ISO-8859-1">
-
- <!--<link rel="stylesheet" type="text/css" href="./styles.css">-->
-
- </head>
-
- <body>
- <a wicket:id="edit" href="UserEdit.html?uid=1" target="_blank" >edit form</a>
- </body>
- </html>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>Index.html</title>
<meta http-equiv="keywords" content="keyword1,keyword2,keyword3">
<meta http-equiv="description" content="this is my page">
<meta http-equiv="content-type" content="text/html; charset=ISO-8859-1">
<!--<link rel="stylesheet" type="text/css" href="./styles.css">-->
</head>
<body>
<a wicket:id="edit" href="UserEdit.html?uid=1" target="_blank" >edit form</a>
</body>
</html>
还要在后台page类Index 中手动添加进组件列表中。
Java代码
- public class Index extends WebPage
- {
- /**
- * Constructor
- */
- public Index()
- {
- PageLink link = new PageLink("edit",new IPageLink());
- add(link);
- }
- }
public class Index extends WebPage
{
/**
* Constructor
*/
public Index()
{
PageLink link = new PageLink("edit",new IPageLink());
add(link);
}
}
add方法是继承自父类org.apache.wicket.MarkupContainer的方法,会将组件添加到其字段children中去.
模板由org.apache.wicket.markup.MarkupParser解析,遇到wicket:id属性的会转换为org.apache.wicket.markup.MarkupElement,
最终将html模板解析成MarkupElement列表,添加到org.apache.wicket.markup.Markup的List<MarkupElement> markupElements集合中,在组件绘制的时候,将其
包装成org.apache.wicket.markup.MarkupStream,会遍历MarkupElement列表,依据组件id获得组件,让每个组件进行绘制--调用方法
void org.apache.wicket.Component.render(MarkupStream markupStream).
具体的主要的解析实现是由org.apache.wicket.markup.parser.XmlPullParser完成的,通过过字符串操作来解析,详见其next方法,并没有使用第三方类库.
2 tapestry实现
tapestry5模板时xml格式,示例Index.tml
Html代码
- <html xmlns:t="http://tapestry.apache.org/schema/tapestry_5_0_0.xsd"> <head>
- <title>Test</title>
- </head>
- <body>
- <h1>Test</h1>
- <h1>Address Book</h1>
- <t:span c="d" >${fi}</t:span>
- <ul>
- <li>
- <a t:type="pagelink" t:page="index" >Create new address</a>
- </li>
- </ul>
- </body> </html>
<html xmlns:t="http://tapestry.apache.org/schema/tapestry_5_0_0.xsd"> <head>
<title>Test</title>
</head>
<body>
<h1>Test</h1>
<h1>Address Book</h1>
<t:span c="d" >${fi}</t:span>
<ul>
<li>
<a t:type="pagelink" t:page="index" >Create new address</a>
</li>
</ul>
</body> </html>
因为已经在模板中指明了这个节点是什么类型的组件,所以,tapestry5就不需要再add组件了,它本身也不提供add方法。
public class Index
Java代码
- {
- @Inject
- private Logger logger;
- private GridDataSource dss;
- private int fi;
- public Index()
- {
- super();
- System.out.println("call ctor.");
- }
- public int getFi()
- {
- return fi;
- }
- public void setFi(int fi)
- {
- this.fi = fi;
- }
- }
{
@Inject
private Logger logger;
private GridDataSource dss;
private int fi;
public Index()
{
super();
System.out.println("call ctor.");
}
public int getFi()
{
return fi;
}
public void setFi(int fi)
{
this.fi = fi;
}
}
tapastry5使用stAx实现的,这篇文章介绍了stax的用法,tapestry5通过注入的方式将org.apache.tapestry5.internal.services.TemplateParserImpl注入到
org.apache.tapestry5.internal.services.ComponentTemplateSourceImpl中的private final TemplateParser parser;字段中,TemplateParserImpl
实际使用的是org.apache.tapestry5.internal.services.StaxTemplateParser,在这里面会使用stax对模板进行解析。它通过节点是否有t:id,t:type属性来判断
是否是一个服务端组件。解析完模板会组建成一个节点列表,再在绘制页面的时候依据这个列表的顺序来调用相应的组件绘制。
逻辑主要在以下的类中
org.apache.tapestry5.internal.parser.ComponentTemplateImpl
org.apache.tapestry5.internal.structure.PageImpl
org.apache.tapestry5.internal.services.PageRenderRequestHandlerImpl
org.apache.tapestry5.internal.services.PageResponseRendererImpl
org.apache.tapestry5.internal.services.PageMarkupRendererImpl
org.apache.tapestry5.internal.services.PageRenderQueueImpl
Page org.apache.tapestry5.internal.pageload.PageLoaderImpl.loadPage(String logicalPageName, Locale locale)
Sopo是可由每个page类来指明模板内容,只要是html格式就可以,示例:
Html代码
- <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
- <html>
- <head>
- <title>test.html</title>
-
- <meta http-equiv="keywords" content="keyword1,keyword2,keyword3">
- <meta http-equiv="description" content="this is my page">
- <meta http-equiv="content-type" content="text/html; charset=ISO-8859-1">
-
- <link rel="stylesheet" type="text/css" href="./styles.css">
- <script type="text/javascript" src="js/hello.js" ></script>
- <script type="text/javascript">
- function $(id){
- return document.getElementById(id);
- }
- function test()
- {
- $('rst').innerHTML=reg.test($('d').value);
- }
- var reg = new RegExp("^([a-zA-Z0-9_\.\-])+\@(([a-zA-Z0-9\-])+\.)+([a-zA-Z0-9]{2,4})+$");
- //var reg = /^([a-zA-Z0-9_\.\-])+\@(([a-zA-Z0-9\-])+\.)+([a-zA-Z0-9]{2,4})+$/i;
- </script>
- </head>
-
- <body>
- h--------
- <!-- hahah -->
- <![CDATA[jkjkjk]]>
- <form action="">
- <label stype="s:Label" id="lab1" >Hello World1<label stype="s:Label" id="lab2" >Hello World3</label></label>
- <input type="password" />
- <label stype="s:Label" id="lab3" >Hello World2</label>
- <input stype="s:Checkbox" id="chk" name="chk" >sss</input>
- <select stype="s:Select" id="sel" name="sel" width="20px" >
- <option stype="s:Option" text="1" ></option>
- <option stype="s:Option" text="2" selected="selected" ></option>
- <option stype="s:Option" text="3" ></option>
- </select>
- <input id="d" type="text" /><button onclick="test();">Test</button>
- <span id="rst">true</span>
- <input type="radio" name="1" >1</input>
- <input type="radio" name="1" >2</input>
- <input type="radio" name="1" onclick="alert(this.value);" >3</input>3
- </form>
- </body>
- </html>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>test.html</title>
<meta http-equiv="keywords" content="keyword1,keyword2,keyword3">
<meta http-equiv="description" content="this is my page">
<meta http-equiv="content-type" content="text/html; charset=ISO-8859-1">
<link rel="stylesheet" type="text/css" href="./styles.css">
<script type="text/javascript" src="js/hello.js" ></script>
<script type="text/javascript">
function $(id){
return document.getElementById(id);
}
function test()
{
$('rst').innerHTML=reg.test($('d').value);
}
var reg = new RegExp("^([a-zA-Z0-9_\.\-])+\@(([a-zA-Z0-9\-])+\.)+([a-zA-Z0-9]{2,4})+$");
//var reg = /^([a-zA-Z0-9_\.\-])+\@(([a-zA-Z0-9\-])+\.)+([a-zA-Z0-9]{2,4})+$/i;
</script>
</head>
<body>
h--------
<!-- hahah -->
<![CDATA[jkjkjk]]>
<form action="">
<label stype="s:Label" id="lab1" >Hello World1<label stype="s:Label" id="lab2" >Hello World3</label></label>
<input type="password" />
<label stype="s:Label" id="lab3" >Hello World2</label>
<input stype="s:Checkbox" id="chk" name="chk" >sss</input>
<select stype="s:Select" id="sel" name="sel" width="20px" >
<option stype="s:Option" text="1" ></option>
<option stype="s:Option" text="2" selected="selected" ></option>
<option stype="s:Option" text="3" ></option>
</select>
<input id="d" type="text" /><button onclick="test();">Test</button>
<span id="rst">true</span>
<input type="radio" name="1" >1</input>
<input type="radio" name="1" >2</input>
<input type="radio" name="1" onclick="alert(this.value);" >3</input>3
</form>
</body>
</html>
它和tapestry有些像,因为模板里面指明了组件类型,所以就不需要再添加了.
Java代码
- public class Index extends Page
- {
- @Override
- public String getTemplate()
- {
- try
- {
- return FileUtils.readFileToString(new File(getSession().getServletContext().getRealPath("Index.html")));
- }
- catch (IOException e)
- {
- throw new RuntimeException(e);
- }
- }
-
- @Override
- public void onLoad()
- {
- Label lab = (Label)getRoot().findComponent("lab3");
- lab.addComponent(new Literal("<a href=\"#\">hi i am dynamic!!</a>"));
- Integer count = (Integer)getViewSate().get("count");
- if (null == count)
- {
- count = 0;
- }
- count ++;
- getViewSate().put("count", count);
- Button btn = new Button("Ok" + count);
- lab.addComponent(btn);
- }
- }
public class Index extends Page
{
@Override
public String getTemplate()
{
try
{
return FileUtils.readFileToString(new File(getSession().getServletContext().getRealPath("Index.html")));
}
catch (IOException e)
{
throw new RuntimeException(e);
}
}
@Override
public void onLoad()
{
Label lab = (Label)getRoot().findComponent("lab3");
lab.addComponent(new Literal("<a href=\"#\">hi i am dynamic!!</a>"));
Integer count = (Integer)getViewSate().get("count");
if (null == count)
{
count = 0;
}
count ++;
getViewSate().put("count", count);
Button btn = new Button("Ok" + count);
lab.addComponent(btn);
}
}
Sopo则是由neko解析模板,生成页面的组件树,web.sopo.template这个包下面包含了所有的模板解析类。每个page都有一个根组件
ComponentRoot web.sopo.page.Page.getRoot(),当开始绘制的时候则会从跟组件开始绘制。它的特点是可以在程序逻辑阶段动态的改变组件树的构造,上面的例子可以看到动态的加了个链接和按钮。使用了它的viewstate特性—存贮页面级变量,这和asp.net很像。
比较
这三种都支持模板(包括页面模板和组件模板),共同特点是模板是html格式,美工可以直接编辑模板,没有讨厌的jsp标签.wicket取经于 tapestry,tapestry取经于asp.net,而sopo也是学asp.net并且和它最像。Wicket需要后台add对应模板的组件,通过匹配,这样做虽然可以动态的决定绘制组件的类型但是也比较繁琐,它类似于swing的方式,但是Mode这个概念入侵很大,通过session来保持状态。tapestry通过模板和组件的绘制来展示页面,不允许你new 一个组件,并且和prototype, scriptaculous集成了,它的performance是这三个中最快的,虽然page和组件都是pojo,但是有注入依赖,到底这个特性有没有用那是见仁见智了。Sopo则是比较灵活,可以动态的修改组件树,和asp.net非常接近,写组件和tapestry一样非常清晰,概念和实现都很单,缺点是它的性能只适用于中小型应用。
Continue reading wicket tapestry5 sopo 模板实现浅析
struts2+tiles时,tiles.xml默认是放在文件夹/web-inf/下面,使用ServletContext的方法查找,一般不需要改动,但是遇到BT的要求需要自定义这个titles的路径查找方式时,可以使用如下方法:
1:在web.xml里面配置自定义监听器:
Xml代码
- <listener>
- <listener-class>demo.MyStrutsTilesListener</listener-class>
- </listener>
2:实现demo.MyStrutsTilesListener这个类,它继承自org.apache.struts2.tiles.StrutsTilesListener,重载方法
Java代码
- protected ServletContext decorate(ServletContext context)
- {
- Map<String, String> INIT = new HashMap<String, String>();
- INIT.put(TilesContainerFactory.CONTAINER_FACTORY_INIT_PARAM, StrutsTilesContainerFactory.class.getName());
- ServletContext servletContext = new MyTilesContext(context,INIT);
-
- return servletContext;
- }
3:实现MyTilesContext:
Java代码
- public class CyberTilesContext extends ConfiguredServletContext
- {
- public static final String PREFIX = "file:///";
-
- public CyberTilesContext(ServletContext context, Map<String, String> initParameters)
- {
- super(context, initParameters);
- }
-
- @Override
- public URL getResource(String string) throws MalformedURLException
- {
- if (!string.startsWith(PREFIX))
- {
- return super.getResource(string);
- }
-
- String path = string.substring(PREFIX.length());
- File file = new File(path);
- if (!file.exists())
- {
- throw new RuntimeException("file " + path + " not founded.");
- }
-
- return file.toURI().toURL();
- }
- }
通过重载getResource方法可以定制自己所需要的查找tiles.xml的方法,上面的例子就是实现以file:///开头查找绝对路径下的tiles.xml。
PS:很不喜欢struts2,对于我来讲,它不适合快速开发,它也不适合大型网站。
Continue reading struts2 自定义tiles.xml文件路径
项目管理工具(project management tool) :
用来支持软件生产中项目管理活动的软件。通常的软件项目管理活动包括项目的计划、调度、通信、费用估算、资源分配以及质量控制等。软件生产是智力密集型的活动,其产品无物理外形,生产状态也“不可见”,因而难于检查和驾驭。软件项目管理工具就是要使这种生产过程成为可见、可控的过程。使用它能帮助进行成本估算、作业调度和任务分配,并制定出成本较低、风险较小的项目开发计划;同时能设法在预计工期和经费之内适当调整项目的安排,以节省时间和人力,从而对软件生产的各个环节进行严格、科学的管理,使项目开发活动获得最佳的进程。
项目管理工具能对项目的任务调度、成本估算、资源分配、预算跟踪、人时统计、配置控制等活动给予帮助,它具有以下一些特征:
(1)覆盖整个软件生存周期;
(2)为项目调度提供多种有效手段;
(3)利用估算模型对软件费用和工作量进行估算;
(4)支持多个项目和子项目的管理;
(5)确定关键路径,松弛时间,超前时间和滞后时间;
(6)对项目组成员和项目任务之间的通信给予辅助;
(7)自动进行资源平衡;
(8)跟踪资源的使用;
(9)生成固定格式的报表和剪裁项目报告。
项目管理工具通常都支持PERT和Gantt图。
PERT是计划评价与评审技术。该技术把网络方法用于工作计划安排的评审和检查。通常以带箭头的边表示活动,边的起讫结点表示活动的开始事件和结束事件,边的长度表示该活动的工作量或工期,各结点的顺序反映了各个活动在时序上的制约关系。利用PERT的网络图能求出关键路径和松弛时间,并能对计划的各个活动和资源分配等进行调整。
Gantt图是一种二维横道图,它广泛用于各种工程活动的进度计划管理。图的横坐标为时间轴,每个活动用一条水平线段表示,其起讫点对应的横坐标值即为该活动的开始和结束时间。
尽管新的项目管理方法和技术会改变人们已经习惯的工作方式,学习和掌握新工具也要花费一些时间,但是使用自动项目管理工具比用手工方法管理有许多优点,如:
(1)能对大型项目进行精确跟踪,使项目经理能及时掌握实际工作进展和实际资源 消耗情况。
(2)能辅助开发PERT,CPM(关键路径方法)和WBS(工作分解结构),自动更新活动网络图和 Gantt图。
(3)能自动计算、自动积累数据、自动生成图形和报表来取代人工计算、调度、统计和文档工作,提高管理工作效率。
国内外已有许多可用于项目管理活动的通用或专用的产品,如
Microsoft公司的Project,
Lotus公司的Notes和Orgnizer,
Primavera System公司的Primavera Project Planner等
Continue reading 【转】项目管理工具
深入浅出OOD(一)
撰文/透明
有物昆成,先天地生。萧呵!谬呵!独立而不改,可以为天地母。吾未知其名,字之曰
道。吾强为之名曰大,大曰逝,逝曰远,远曰反。道大,天大,地大,王亦大。
——《道德经》,第二十五章
软件不软
从 60 年代的软件危机,到今天传统软件工程方法处处碰壁的处境,都说明一个问题:
软件不软(Software is Hard)[Martin, 95]。说实话,软件是一块硬骨头,真正开发过软
件的人都会有此感觉。一个应用总是包含无数错综复杂的细节,而软件开发者则要把所
有这些细节都组织起来,使之形成一个可以正常运转的程序,这实在不是一件简单的事。
为什么会这样?举个例子来说:用户可以很轻松地说“我要一个字处理软件”,他觉得
“字处理软件”这样一个概念是再清楚不过的了,根本不需要更多的描述;而真正开发
一个字处理软件却是一件困难无比的事情——我曾经亲眼看到开发字处理软件的人们
是怎样受尽折磨的。为什么表述一个概念很容易,而实现一个概念很困难?因为人们太
擅长抽象、太擅长剥离细节问题了。
软件不软,症结就在这里:用户很容易抽象地表达自己的需求,而这种抽象却很难转化
为程序代码。软件不软,因为很简单的设想也需要大量的时间去实现;软件不软,因为
满足用户的需求和期望实在太困难;软件不软,因为软件太容易让用户产生幻想。
而另一方面,计算机硬件技术却在飞速发展。从几十年前神秘的庞然大物,到现在随身
携带的移动芯片;从每秒数千次运算到每秒上百亿次运算。当软件开发者们还在寻找能
让软件开发生产力提高一个数量级的“银弹”[Brooks, 95]时,硬件开发的生产力早已提
升了百倍千倍。这是为什么?
硬件工程师们能够如此高效,是因为他们都很懒惰。他们永远恪守“不要去重新发明轮
子”的古训,他们尽量利用别人的成果。你看到有硬件工程师自己设计拨码开关的吗?
你看到有硬件工程师自己设计低通滤波电路的吗?你看到有硬件工程师自己设计计时
器的吗?他们有一套非常好的封装技术,他们可以把电路封装在一个接插件里面,只露
出接口。别人要用的时候,只管按照接口去用,完全不必操心接插件内部的实现。
而软件工程师们呢?在 STL成为C++标准之前(甚至之后),每个C++程序员都写过自
己的排序算法和链表,并认为自己比别人写得更好⋯⋯真是令人伤心。
OOD 可以让软件稍微“软”一点
软件不软,不过OOD可以帮助它稍微“软”一点。OOD为我们提供了封装某一层面上
的功能和复杂性的工具。使用OOD,我们可以创建黑箱软件模块,将一大堆复杂的东
西藏到一个简单的接口背后。然后,软件工程师们就可以使用标准的软件技术把这些黑
箱组合起来,形成他们想要的应用程序。
Grady Booch 把这些黑箱称为类属(class category),现在我们则通常把它们称为“组件
(component)”。类属是由被称为类(class)的实体组成的,类与类之间通过关联
(relationship)结合在一起。一个类可以把大量的细节隐藏起来,只露出一个简单的接
口,这正好符合人们喜欢抽象的心理。所以,这是一个非常伟大的概念,因为它给我们
提供了封装和复用的基础,让我们可以从问题的角度来看问题,而不是从机器的角度来
看问题。
软件的复用最初是从函数库和类库开始的,这两种复用形式实际上都是白箱复用。到 90
年代,开始有人开发并出售真正的黑箱软件模块:框架(framework)和控件(control)。
框架和控件往往还受平台和语言的限制,现在软件技术的新潮流是用SOAP 作为传输介
质的Web Service,它可以使软件模块脱离平台和语言的束缚,实现更高程度的复用。
但是想一想,其实Web Service 也是面向对象,只不过是把类与类之间的关联用XML
来描述而已[Li, 02]。在过去的十多年里,面向对象技术对软件行业起到了极大的推动作
用。在可以预测的将来,它仍将是软件设计的主要技术——至少我看不到有什么技术可
以取代它的。
上面,我向读者介绍了一些背景知识,也稍微介绍了 OOD 的好处。下面,我将回答几
个常见的问题,希望能借这几个问题让读者看清OOD 的轮廓。
什么是 OOD?
面向对象设计(Object-Oriented Design,OOD)是一种软件设计方法,是一种工程化规
范。这是毫无疑问的。按照Bjarne Stroustrup 的说法,面向对象的编程范式(paradigm)
是[Stroustrup, 97]:
l 决定你要的类;
l 给每个类提供完整的一组操作;
l 明确地使用继承来表现共同点。
由这个定义,我们可以看出:OOD 就是“根据需求决定所需的类、类的操作以及类之
间关联的过程”。
OOD 的目标是管理程序内部各部分的相互依赖。为了达到这个目标,OOD要求将程序
分成块,每个块的规模应该小到可以管理的程度,然后分别将各个块隐藏在接口
(interface)的后面,让它们只通过接口相互交流。比如说,如果用OOD 的方法来设计
一个服务器-客户端(client-server)应用,那么服务器和客户端之间不应该有直接的依
赖,而是应该让服务器的接口和客户端的接口相互依赖。
这种依赖关系的转换使得系统的各部分具有了可复用性。还是拿上面那个例子来说,客
户端就不必依赖于特定的服务器,所以就可以复用到其他的环境下。如果要复用某一个
程序块,只要实现必须的接口就行了。
OOD 是一种解决软件问题的设计范式(paradigm),一种抽象的范式。使用OOD 这种
设计范式,我们可以用对象(object)来表现问题领域(problem domain)的实体,每个
对象都有相应的状态和行为。我们刚才说到:OOD 是一种抽象的范式。抽象可以分成
很多层次,从非常概括的到非常特殊的都有,而对象可能处于任何一个抽象层次上。另
外,彼此不同但又互有关联的对象可以共同构成抽象:只要这些对象之间有相似性,就
可以把它们当成同一类的对象来处理。
OOD 到底从哪儿来?
有很多人都认为:OOD是对结构化设计(Structured Design,SD)的扩展,其实这是不
对的。OOD 的软件设计观念和SD 完全不同。SD 注重的是数据结构和处理数据结构的
过程。而在OOD 中,过程和数据结构都被对象隐藏起来,两者几乎是互不相关的。不
过,追根溯源,OOD 和SD 有着非常深的渊源。
1967 年前后,OOD 和SD 的概念几乎同时诞生,它们分别以不同的方式来表现数据结
构和算法。当时,围绕着这两个概念,很多科学家写了大量的论文。其中,由Dijkstra
和Hoare 两人所写的一些论文讲到了“恰当的程序控制结构”这个话题,声称goto 语句
是有害的,应该用顺序、循环、分支这三种控制结构来构成整个程序流程。这些概念发
展构成了结构化程序设计方法;而由Ole-Johan Dahl 所写的另一些论文则主要讨论编程
语言中的单位划分,其中的一种程序单位就是类,它已经拥有了面向对象程序设计的主
要特征。
这两种概念立刻就分道扬镳了。在结构化这边的历史大家都很熟悉:NATO会议采纳了
Dijkstra 的思想,整个软件产业都同意goto 语句的确是有害的,结构化方法、瀑布模型
从70 年代开始大行其道。同时,无数的科学家和软件工程师也帮助结构化方法不断发
展完善,其中有很多今天足以使我们振聋发聩的名字,例如Constantine、Yourdon、
DeMarco 和Dijkstra。有很长一段时间,整个世界都相信:结构化方法就是拯救软件工
业的“银弹”。当然,时间最后证明了一切。
而此时,面向对象则在研究和教育领域缓慢发展。结构化程序设计几乎可以应用于任何
编程语言之上,而面向对象程序设计则需要语言的支持1,这也妨碍了面向对象技术的
发展。实际上,在60 年代后期,支持面向对象特性的语言只有Simula-67 这一种。到
70 年代,施乐帕洛阿尔托研究中心(PARC)的Alan Key 等人又发明了另一种基于面向
对象方法的语言,那就是大名鼎鼎的Smalltalk。但是,直到80 年代中期,Smalltalk 和
另外几种面向对象语言仍然只停留在实验室里。
到 90 年代,OOD突然就风靡了整个软件行业,这绝对是软件开发史上的一次革命。不
过,登高才能望远,新事物总是站在旧事物的基础之上的。70 年代和80 年代的设计方
法揭示出许多有价值的概念,谁都不能也不敢忽视它们,OOD 也一样。
OOD 和传统方法有什么区别?
还记得结构化设计方法吗?程序被划分成许多个模块,这些模块被组织成一个树型结
构。这棵树的根就是主模块,叶子就是工具模块和最低级的功能模块。同时,这棵树也
表示调用结构:每个模块都调用自己的直接下级模块,并被自己的直接上级模块调用。
那么,哪个模块负责收集应用程序最重要的那些策略?当然是最顶端的那些。在底下的
那些模块只管实现最小的细节,最顶端的模块关心规模最大的问题。所以,在这个体系
结构中越靠上,概念的抽象层次就越高,也越接近问题领域;体系结构中位置越低,概
念就越接近细节,与问题领域的关系就越少,而与解决方案领域的关系就越多。
但是,由于上方的模块需要调用下方的模块,所以这些上方的模块就依赖于下方的细节。
换句话说,与问题领域相关的抽象要依赖于与问题领域无关的细节!这也就是说,当实
现细节发生变化时,抽象也会受到影响。而且,如果我们想复用某一个抽象的话,就必
须把它依赖的细节都一起拖过去。
而在 OOD 中,我们希望倒转这种依赖关系:我们创建的抽象不依赖于任何细节,而细
节则高度依赖于上面的抽象。这种依赖关系的倒转正是OOD 和传统技术之间根本的差
异,也正是OOD 思想的精华所在。
OOD 能给我带来什么?
问这个问题的人,脑子里通常是在想“OOD 能解决所有的设计问题吗?”没有银弹。
1 我听见有人说“我可以用 C 语言实现面向对象”,不过我希望你不会说“我也喜欢这样做”。很明显,
如果没有语言特性的支持,面向对象方法将寸步难行。其实结构化设计也是一样,不过几乎所有的编
程语言都提供了对三种基本流程结构的支持,所以基本不会遇到这个问题。
OOD 也不是解决一切设计问题、避免软件危机、捍卫世界和平⋯⋯的银弹。OOD 只是
一种技术。但是,它是一种优秀的技术,它可以很好地解决目前的大多数软件设计问题
——当然,这要求设计者有足够的能力。
OOD 可能会让你头疼,因为要学会它、掌握它是很困难的;OOD甚至会让你失望,因
为它也并不成熟、并不完美。OOD 也会给你带来欣喜,它让你可以专注于设计,而不
必操心那些细枝末节;OOD 也会使你成为一个更好的设计师,它能提供给你很好的工
具,让你能开发出更坚固、更可维护、更可复用的软件。
C++是一种“真正的”面向对象编程语言吗?
最后这个问题和我们今天的主题关系不大,不过这是一个由来已久的问题,而且以后也
不一定会有合适的时机说明这个问题,所以今天一起回答了。
很多人都觉得 C++缺少“真正的”面向对象语言所必须的一些特性,例如垃圾收集
(garbage collection)、多分配(multiple-dispatch)之类的。但是,缺少这些特性并不影
响开发者们用C++实现面向对象的设计思路。
在我看来,任何语言,只要它直接支持面向对象设计的实现,那它就是“真正的”面向
对象语言。用这个标准来评价,C++是完全符合的:它直接支持继承、多态、封装和抽
象,而这些才是面向对象最重要的。而VB 和C 这样的语言不能直接支持这些(尽管可
以用特殊的技巧来实现),所以不是“真正的”面向对象语言。
参考书目
l [Brooks, 95] Frederick Brooks, The Mythical Man-Month, Addison-Wesley, 1995.
l [Li, 02] 李维,《Delphi 6/Kylix 2 SOAP/Web Service 程序设计篇》,机械工业出
版社,2002 年。
l [Martin, 95] Robert Martin, Designing Object-Oriented C++ Applications Using
the Booch Method, Prentice-Hall, 1995.
l [Stroustrup, 97] Bjarne Stroustrup, The C++ Programming Language (Special
Edition), Addison-Wesley, 1997.
Continue reading 【转】深入浅出OOD(一)
见文章 http://kazge.com/archives/275.html 讲得比较详细。
再看 http://www.ibm.com/developerworks/cn/java/j-nioserver/
看看 http://zddava.iteye.com/blog/835244
综上所述,我认为nio并不能对web 服务器性能提高很大因为每个servlet还是一个线程,这样与没有使用nio的情况是一样的。??
现在看看[IO 接口,设备](https://blog.kazge.com/%E8%AE%A1%E7%AE%97%E6%9C%BA%E5%9F%BA%E7%A1%80/2011/10/21/io-e6-8e-a5-e5-8f-a3-ef-bc-8c-e8-ae-be-e5-a4-87-ef-bc-8c-e6-93-8d-e4-bd-9c/),这篇文章分析的比较细。nio跟更像是多路io,性能还是能够提升的!
Continue reading nio 和 web 线程
共性:都是从现有的用例中抽取出公共的那部分信息,作为一个单独的用例,然后通后过不同的方法来重用这个公共的用例,以减少模型维护的工作量。
1
、包含(include)
包含关系:使用包含(Inclusion)用例来封装一组跨越多个用例的相似动作(行为片断),以便多个基(Base)用例复用。基用例控制与包含用例的 关系,以及被包含用例的事件流是否会插入到基用例的事件流中。基用例可以依赖包含用例执行的结果,但是双方都不能访问对方的属性。 包含关系对典型的应用就是复用,也就是定义中说的情景。但是有时当某用例的事件流过于复杂时,为了简化用例的描述,我们也可以把某一段事件流抽象成为一个被包含的用例;相反,用例划分太细时,也可以抽象出一个基用例,来包含这些细颗粒的用例。这种情况类似于在过程设计语言中,将程序的某一段算法封装成一个子过程,然后再从主程序中调用这一子过程。
例如:业务中,总是存在着维护某某信息的功能,如果将它作为一个用例,那新建、编辑以及修改都要在用例详述中描述,过于复杂;如果分成新建用例、编辑用例和删除用例,则划分太细。这时包含关系可以用来理清关系。

2、扩展(extend)
扩展关系:将基用例中一段相对独立并且可选的动作,用扩展(Extension)用例加以封装,再让它从基用例中声明的扩展点(Extension Point)上进行扩展,从而使基用例行为更简练和目标更集中。扩展用例为基用例添加新的行为。扩展用例可以访问基用例的属性,因此它能根据基用例中扩展点的当前状态来判断是否执行自己。但是扩展用例对基用例不可见。
对于一个扩展用例,可以在基用例上有几个扩展点。 例如,系统中允许用户对查询的结果进行导出、打印。对于查询而言,能不能导出、打印查询都是一样的,导出、打印是不可见的。导入、打印和查询相对独立,而且为查询添加了新行为。因此可以采用扩展关系来描述:
4、泛化(generalization)
泛化关系:子用例和父用例相似,但表现出更特别的行为;子用例将继承父用例的所有结构、行为和关系。子用例可以使用父用例的一段行为,也可以重载它。父用例通常是抽象的。在实际应用中很少使用泛化关系,子用例中的特殊行为都可以作为父用例中的备选流存在。
例如,业务中可能存在许多需要部门领导审批的事情,但是领导审批的流程是很相似的,这时可以做成泛化关系表示:

上面是我参考的一篇文章,觉得将三种关系的区别讲得很清晰,在此基础上结合自己的系统,对项目(在线购物系统)的用例做了整体的描绘。 *****************************************************************
(1)系统整体用例图




按照先整体用例,后子系统用例来进行描绘的,欢迎大家提出好的建议!
转:UML中扩展和泛化的区别
泛化表示类似于OO术语“继承”或“多态”。UML中的Use Case泛化过程是将不同Use Case之间的可合并部分抽象成独立的父Use Case,并将不可合并部分单独成各自的子Use Case;包含以及扩展过程与泛化过程类似,但三者对用例关系的优化侧重点是不同的。如下:
●泛化侧重表示子用例间的互斥性;
●包含侧重表示被包含用例对Actor提供服务的间接性;
●扩展侧重表示扩展用例的触发不定性;详述如下:
既然用例是系统提供服务的UML表述,那么服务这个过程在所有用例场景中是必然发生的,但发生按照发生条件可分为如下两种情况:
⒈无条件发生:肯定发生的;
⒉有条件发生:未必发生,发生与否取决于系统状态;
因此,针对用例的三种关系结合系统状态考虑,泛化与包含用例属于无条件发生的用例,而扩展属于有条件发生的用例。进一步,用例的存在是为Actor提供服 务,但用例提供服务的方式可分为间接和直接两种,依据于此,泛化中的子用例提供的是直接服务,而包含中的被包含用例提供的是间接服务。同样,扩展用例提供的也是直接服务,但扩展用例的发生是有条件的。
另外一点需要提及的是:泛化中的子用例和扩展中的扩展用例均可以作为基本用例事件的备选择流而存在。
试题中抽象用例和使用关系我觉得就是指包含关系中的描述。
Continue reading 【转】UML用例图中包含(include)、扩展(extend)和泛化(generalization)三种关系详解
要检查默认的启动/停止/状态检查命令是否是你设置的对应的mysql服务的名称 home/serveradmin/manage server instance
例如sc start mysql51 中mysql51 要对应实际的服务名称(不区分大小写)
MySQL Workbench is a visual database design tool recently released by MySQL AB. The tool is specifically for designing MySQL database.
MySQL Workbench has many functions and features; this article by Djoni Darmawikarta shows some of them by way of an example. We’ll build a physical data model for an order system where an order can be a sale order or a purchase order, and then, forward-engineer our model into an MySQL database.
MySQL Workbench is a visual database design tool recently released by MySQL AB. The tool is specifically for designing MySQL database.
What you build in MySQL Workbench is called physical data model. A physical data model is a data model for a specific RDBMS product; the model in this article will have some MySQL unique specifications. We can generate (forward-engineer) the database objects from its physical model, which in addition to tables and their columns, can also include other objects such as view.
MySQL Workbench has many functions and features; this article by Djoni Darmawikarta shows some of them by way of an example. We’ll build a physical data model for an order system where an order can be a sale order or a purchase order; and then, forward-engineer our model into an MySQL database.
The physical model of our example in EER diagram will look like in the following MySQL Workbench screenshot.

Creating ORDER Schema
Let’s first create a schema where we want to store our order physical model. Click the + button (circled in red).

Change the new schema’s default name to ORDER. Notice that when you’re typing in the schema name, its tab name on the Physical Schemata also changes accordingly—a nice feature.
The order schema is added to the Catalog (I circled the order schema and its objects in red).

Close the schema window. Confirm to rename the schema when prompted.

Creating Order Tables
We’ll now create three tables that model the order: ORDER table and its two subtype tables: SALES_ORDER and PURCHASE_ORDER, in the ORDER schema. First of all, make sure you select the ORDER schema tab, so that the tables we’ll create will be in this schema.
We’ll create our tables as EER diagram (EER = Enhanced Entity Relationship). So, double-click the Add Diagram button.

Select (click) the Table icon, and then move your mouse onto the EER Diagram canvas and click on the location you want to place the first table.


Repeat for the other two tables. You can move around the tables by dragging and dropping.

Next, we’ll work on table1, which we’ll do so using the Workbench’s table editor. We start the table editor by right-clicking the table1 and selecting Edit Table.

Next, we’ll work on table1, which we’ll do so using the Workbench’s table editor. We start the table editor by right-clicking the table1 and selecting Edit Table.
Rename the table by typing in ORDER over table1.

We’ll next add its columns, so select the Columns tab. Replace idORDER column name with ORDER_NO.

Select INT as the data type from the drop-down list.

We’d like this ORDER_NO column to be valued incrementally by MySQL database, so we specify it as AI column (Auto Increment).
AI is a specific feature of MySQL database.

You can also specify other physical attributes of the table, such as its Collation; as well as other advanced options, such as its trigger and partioning (the Trigger and Partioning tabs).

Notice that on the diagram our table1 has changed to ORDER, and it has its first column, ORDER_NO. In the Catalog you can also see the three tables.
The black dots on the right of the tables indicate that they’ve been included in an diagram.

If you expand the ORDER folder, you’ll see the ORDER_NO column. As we define the column as a primary key, it has a key icon on its left.

Back to the table editor, add the other columns: ORDER_DATE and ORDER_TYPE. The ORDER_TYPE can have one of two values: S for sales order, P for purchase order. As sales order is more common, we’d like to specify it as the column’s default value.
You add the next column by double-clicking the white space below the last column.

In the same way, create the SALES_ORDER table and its columns.

Lastly, create the PURCHASE_ORDER table and its columns.

Create Relationships
We have now created all three tables and their columns. We haven’t done yet with our model; we still need to create the subtype relationships of our tables.
The SALES_ORDER is a subtype of ORDER, implying their relationship is 1:1 with the SALES_ORDER as the child and ORDER the parent, and also the ORDER’s key migrated to the SALES_ORDER. So, select (click) the 1:1 identifying relationship icon, and click it on the SALES_ORDER table and then ORDER table.

Notice that the icon changes to a hand with the 1:1 relationship when you click it to the tables.


The 1:1 relationship is set; the ORDER_NO primary key is migrated and becomes the primary key of the SALES_ORDER table.

Next, create the PURCHASE_ORDER to ORDER relationship, which is also 1:1 identifying relationship.

We have now completed designing our tables and their relationships; let’s save our model as ORDER.mwb.


Generate DDL and Database
The final step of our data modeling in this article is generating the model into MySQL database. We’ll first generate the DDL (SQL CREATE script), and then execute the script.
From the File | Export menu, select Forward Engineer SQL CREATE Script.



Lastly, execute the saved SQL CREATE script. We execute the script outside of MySQL Workbench; for example, we can execute it in a MySQL command console.


You can also confirm that the tables have been created.

Summary
This article shows you how to build a MySQL physical data model visually in MySQL Workbench, and generate the model into its MySQL database.
Continue reading MySQL Workbench使用方法