S sky1000 Unregistered / Unconfirmed GUEST, unregistred user! 2008-09-11 #1 项目中会常常和第三方公司做接口,有时是要数据,有时是提供数据.大家提供一些好的实现方法吧?有时用ORACLE代码来完成,有时要做一个单独程序来运行,但这样维护起来太麻烦.
S szhcracker Unregistered / Unconfirmed GUEST, unregistred user! 2008-09-11 #2 1、多用配置文件、存储过程、视图等,这样尽可能修改数据库上的东东而不用改代码;<br>2、尽量用标准的格式并预留字段等;
S szhcracker Unregistered / Unconfirmed GUEST, unregistred user! 2008-09-11 #3 给你一段网文:<br>摘要:我们在设计系统接口时,经常会遇到这样的问题:<br>我们的接口应该提供多少方法才合适?<br>我们的接口应该提供"原子方法"还是"复合方法"?<br>我们的接口是否应该封装(或者,能否封装)所有的细节?<br>接口的设计需要考虑用户的使用习惯、使用的方便程度、使用的安全程度,根据我的编程经验,下面会详细<br>讨论接口设计的2个需要权衡的方面:接口的单一化 & 复合化。<br>接口<br>接口提供了不同系统之间或者系统不同组件之间的界定。在软件中,接口提供了一个屏障,从而从实现中分<br>离目标,从具体中分离抽象,从作者中分离用户。<br><br>站在用户的角度看,一个接口建立并命名了一个目标对象的使用方法。一些约束(例如:编译时的类型系<br>统、运行时的异常机制及返回值)使得类作者的目的得以体现和加强。供给(affordances)指事物的被感<br>知的真实的属性,这些属性可以决定事物使用的可能方法,供给提供了对事物操作的线索。<br><br>类设计者的一个职责便是在接口中减小约束与供给之间的隔阂、匹配目标以及一定程度上的自由度,尽可能<br>减小错误使用目标对象的可能。<br><br>封装<br>对于封装来说,远不止数据私有那么简单。在设计中,封装往往会涉及到自我包含(self-containment)。<br>如果一个类需要你知道如何调用它方法(e.g. 在一个线程的环境中,在一个方法调用后调用另一个方法,<br>你必须明确地同步对象),那么它的封装性就不如将所有这些全部包含并隐藏的类(e.g. 这个类是thread-<br>safe的)好。前一个设计存在着设计的漏洞,它的许多限定条件是模糊的,而且把部分责任推给了用户,而<br>不是让类提供者做这些工作来完成类的设计。<br><br>在空间或者时间上分离方法的执行(例如,线程,远程方法调用,消息队列),能够对设计的正确性和效率<br>产生意义深远的影响。这种分离带来的结果是不可忽视的:<br><br>并发引入了不确定性和环境(context)选择的开销;<br>分布引入了回调的开销,这些开销可能不断增加,而且会导致错误。<br>这些是设计的问题,修改它们可不是象修改bug那样简单。<br><br>如果一个接口主要由存取方法(set和get方法)组成,每个方法都相应的直接指向某个私有域,那么它的封<br>装性会很差。接口中的域存取方法通常是不会提供信息的:他们在对象的使用中不能通讯、简单化和抽象<br>化,这通常会导致代码冗长,并且容易出错。<br><br>所以,我们首先考虑接口设计的第一个原则:<br><br>命令与查询分离(Command-Query Separation)<br>要求:保证一个方法不是命令(Command)就是查询(Query)<br><br>定义:<br> 查询:当一个方法返回一个值来回应一个问题的时候,它就具有查询的性质;<br> 命令:当一个方法要改变对象的状态的时候,它就具有命令的性质;<br><br>通常,一个方法可能是纯的Command模式或者是纯的Query模式,或者是两者的混合体。在设计接口时,如果<br>可能,应该尽量使接口单一化,保证方法的行为严格的是命令或者是查询,这样查询方法不会改变对象的状<br>态,没有副作用(side effects),而会改变对象的状态的方法不可能有返回值。也就是说:如果我们要问<br>一个问题,那么就不应该影响到它的答案。实际应用,要视具体情况而定,语义的清晰性和使用的简单性之<br>间需要权衡。<br><br>例如,在java.util.Iterator中,hasNext可以被看作一种查询,remove是一种命令,next合并了命令和查<br>询:<br>public interface Iterator{<br>boolean hasNext();<br>Object next();<br>void remove();<br>}<br><br>这里,如果不将一个Iterator对象的当前值向前到下一个的话,就不能够查询一个Iterator对象。如果没有<br>提供一个复合方法next,我们将需要定义一系列的命令方法,例如:初始化(initialization)、继续<br>(continuation)、访问(access)和前进(advance),它们虽然清晰定义了每个动作,但是,客户代码过于复<br>杂:<br>for(initialization; continuation condition; advance){<br>... access for use ...<br>}<br><br>将Command和Query功能合并入一个方法,方便了客户的使用,但是,降低了清晰性,而且,可能不便于基于<br>断言的程序设计并且需要一个变量来保存查询结果:<br>Iterator iterator = collection.iterator();<br>while(iterator.hasNext(){<br>Object current = iterator.next();<br>... use current...<br>}<br><br>下面,我们考虑接口设计的第二个原则:<br><br>组合方法(Combined Method)<br>组合方法经常在线程和分布环境中使用,来保证正确性并改善效率。<br><br>一些接口提供大量的方法,起初,这些方法看来是最小化的,而且相关性强。然而,在使用的过程中,一些<br>接口显现得过于原始,它们过于简单化,从而迫使类用户用更多的工作来实现普通的任务,并且,方法之间<br>的先后顺序及依赖性比较强(即,暂时耦合)。这导致了代码重复,而且非常麻烦和容易出错。<br><br>一些需要同时执行成功的方法,在多线程、异常、和分布的情况下会遇到麻烦。如果两个动作需要同时执<br>行,它们由两个独立的方法进行描述,必须都完全成功的执行,否则会导致所有动作的回滚。<br><br>线程的引入使这种不确定性大大增加。一系列方法同时调用一个易变的(mutable)对象,如果这个对象在线<br>程之间共享,即使我们假设单独的方法是线程安全的,也无法确保结果是意料之中的。看下面对Event<br>Source的接口,它允许安置句柄和对事件的查询:<br>interface EventSource{<br>Handler getHandler(Event event);<br>void installHandler(Event event, Handler newHandler);<br>}<br><br>线程之间的交叉调用可能会引起意想不到的结果。假设source域引用一个线程共享的对象,对象很可能在<br>1、2之间被另一个线程安装了一个新的句柄:<br>class EventSourceExample{<br>public void example(Event event, Handler newHandler){<br>oldHandler = eventSource.getHandler(event); // 1<br>//对象很可能在这里被另一个线程安装了一个新的句柄<br>eventSource.installHandler(event, newHandler); // 2<br>}<br>private EventSource eventSource;<br>private Handler oldHandler;<br>}<br><br>为了解决问题,也需要由类的使用者而不是类的设计者来完成:<br>class EventSourceExample{<br>public void example(Event event, Handler newHandler){<br>synchronized(eventSource){<br>oldHandler = eventSource.getHandler(event);<br>eventSource.installHandler(event, newHandler);<br>}<br>}<br>private EventSource eventSource;<br>private Handler oldHandler;<br>}<br><br>我们假设:目标对象eventSource是远程的,执行每一个方法体的时间和通讯的延迟相比是很短的。在这个<br>例子中,eventSource的方法被调用了两次,并可能在其他的实例中重复多次,因而,开销也是至少两倍。<br><br>此外还有一个问题是对外部的synchronized同步块的使用需求。对synchronized块的使用之所以会失败,主<br>要因为我们通过代理对象来完成工作,所以,调用者的synchronized块,同步的是代理对象而不是最终的目<br>标对象,调用者不可能对其行为做太多的保证。<br><br>Combined Method必须在分布的环境,或者,线程环境中同时执行。它反映了用户直接的应用,恢复策略和<br>一些笨拙的方法被封装到Combined Method中,并简化了接口,减少了接口中不需要的累赘。Combined<br>Method的效果是支持一种更像事务处理风格的设计。<br><br>在一个组合的Command-Query中提供一个单独的Query方法通常是合理的。提供分离的Command方法是不太常<br>见的,因为Combined Method可以完成这一工作,只要调用者简单的忽略返回结果。如果返回一个结果招致<br>一个开销的话,才可能会提供一个单独的Command方法。<br><br>回到前一个例子中,如果installHandler method返回上一次安装的句柄,则设计变得更加简单和独立:<br>interface EventSource{<br>Handler installHandler(Event event, Handler newHandler);<br>}<br><br>客户代码如下:<br>class EventSourceExample{<br>public void example(Event event, Handler newHandler){<br>oldHandler = eventSource.installHandler(event, newHandler);<br>}<br>private EventSource eventSource;<br>private Handler oldHandler;<br>}<br><br>这样,我们给调用者提供了一个更加安全的接口,并且不再需要他们解决线程的问题。从而降低了风险和代<br>码量,将类设计的职责全部给了类设计者而不是推给用户,即使有代理对象的出现也不会影响到正确性。<br><br>一个Combined Method可以是许多Query的集合,许多Command的集合,或者两者兼有。这样,它可能补充<br>Command、Query方法,也可能与之相抵触。当冲突发生的时候,优先选择Combined Method会产生一个不同<br>的正确性和适用性。<br><br>在另一个例子中,我们考虑获得资源的情况。假设,在下面的接口中,方法acquire在资源可用前阻塞:<br>interface Resource{<br>boolean isAcquired();<br>void acquire();<br>void release();<br>}<br><br>类似于下面的代码会在一个线程系统中推荐使用:<br>class ResourceExample{<br>public void example(){<br>boolean acquired = false;<br>synchronized(resource){<br>if(!resource.isAcquired())<br>resource.acquire();<br>else<br>acquired = true;<br>}<br>if(!acquired)<br>...<br>}<br>private Resource resource;<br>}<br><br>然而,即使我们放弃可读性和易用性,这样的设计也不是一个Command-Query分离的设计。如果引入了代<br>理,它就会失败:<br>class ActualResource implements Resource {...}<br>class ResourceProxy implements Resource {...}<br><br>如果用户既可以通过ActualResource来完成工作,也可以通过ResourceProxy来完成工作,而且,<br>ActualResource和ResourceProxy都没有处理同步,则synchronized块可能会失败。因为,既然我们可以通<br>过代理对象ResourceProxy来完成工作,那么,调用者的synchronized块,同步的就是代理对象<br>ResourceProxy而不是最终的目标对象ActualResource。<br><br>一个Combined Method解决了这个问题,它使并发和间接性更加透明。<br>interface Resource{<br>boolean tryAcquire();<br>}<br><br>下面的代码清晰、简单并且正确:<br>class ResourceExample{<br>public void example(){<br>if(!resource.tryAcquire())<br>...<br>}<br>private Resource resource;<br>}<br><br>Combined Method带来的一个结果是使一些测试和基于断言的程序设计变得十分笨拙,然而,它适合解决线<br>程和分布问题。<br><br>实际应用中,接口应该单一化还是复合化,要视具体情况而定。
给你一段网文:<br>摘要:我们在设计系统接口时,经常会遇到这样的问题:<br>我们的接口应该提供多少方法才合适?<br>我们的接口应该提供"原子方法"还是"复合方法"?<br>我们的接口是否应该封装(或者,能否封装)所有的细节?<br>接口的设计需要考虑用户的使用习惯、使用的方便程度、使用的安全程度,根据我的编程经验,下面会详细<br>讨论接口设计的2个需要权衡的方面:接口的单一化 & 复合化。<br>接口<br>接口提供了不同系统之间或者系统不同组件之间的界定。在软件中,接口提供了一个屏障,从而从实现中分<br>离目标,从具体中分离抽象,从作者中分离用户。<br><br>站在用户的角度看,一个接口建立并命名了一个目标对象的使用方法。一些约束(例如:编译时的类型系<br>统、运行时的异常机制及返回值)使得类作者的目的得以体现和加强。供给(affordances)指事物的被感<br>知的真实的属性,这些属性可以决定事物使用的可能方法,供给提供了对事物操作的线索。<br><br>类设计者的一个职责便是在接口中减小约束与供给之间的隔阂、匹配目标以及一定程度上的自由度,尽可能<br>减小错误使用目标对象的可能。<br><br>封装<br>对于封装来说,远不止数据私有那么简单。在设计中,封装往往会涉及到自我包含(self-containment)。<br>如果一个类需要你知道如何调用它方法(e.g. 在一个线程的环境中,在一个方法调用后调用另一个方法,<br>你必须明确地同步对象),那么它的封装性就不如将所有这些全部包含并隐藏的类(e.g. 这个类是thread-<br>safe的)好。前一个设计存在着设计的漏洞,它的许多限定条件是模糊的,而且把部分责任推给了用户,而<br>不是让类提供者做这些工作来完成类的设计。<br><br>在空间或者时间上分离方法的执行(例如,线程,远程方法调用,消息队列),能够对设计的正确性和效率<br>产生意义深远的影响。这种分离带来的结果是不可忽视的:<br><br>并发引入了不确定性和环境(context)选择的开销;<br>分布引入了回调的开销,这些开销可能不断增加,而且会导致错误。<br>这些是设计的问题,修改它们可不是象修改bug那样简单。<br><br>如果一个接口主要由存取方法(set和get方法)组成,每个方法都相应的直接指向某个私有域,那么它的封<br>装性会很差。接口中的域存取方法通常是不会提供信息的:他们在对象的使用中不能通讯、简单化和抽象<br>化,这通常会导致代码冗长,并且容易出错。<br><br>所以,我们首先考虑接口设计的第一个原则:<br><br>命令与查询分离(Command-Query Separation)<br>要求:保证一个方法不是命令(Command)就是查询(Query)<br><br>定义:<br> 查询:当一个方法返回一个值来回应一个问题的时候,它就具有查询的性质;<br> 命令:当一个方法要改变对象的状态的时候,它就具有命令的性质;<br><br>通常,一个方法可能是纯的Command模式或者是纯的Query模式,或者是两者的混合体。在设计接口时,如果<br>可能,应该尽量使接口单一化,保证方法的行为严格的是命令或者是查询,这样查询方法不会改变对象的状<br>态,没有副作用(side effects),而会改变对象的状态的方法不可能有返回值。也就是说:如果我们要问<br>一个问题,那么就不应该影响到它的答案。实际应用,要视具体情况而定,语义的清晰性和使用的简单性之<br>间需要权衡。<br><br>例如,在java.util.Iterator中,hasNext可以被看作一种查询,remove是一种命令,next合并了命令和查<br>询:<br>public interface Iterator{<br>boolean hasNext();<br>Object next();<br>void remove();<br>}<br><br>这里,如果不将一个Iterator对象的当前值向前到下一个的话,就不能够查询一个Iterator对象。如果没有<br>提供一个复合方法next,我们将需要定义一系列的命令方法,例如:初始化(initialization)、继续<br>(continuation)、访问(access)和前进(advance),它们虽然清晰定义了每个动作,但是,客户代码过于复<br>杂:<br>for(initialization; continuation condition; advance){<br>... access for use ...<br>}<br><br>将Command和Query功能合并入一个方法,方便了客户的使用,但是,降低了清晰性,而且,可能不便于基于<br>断言的程序设计并且需要一个变量来保存查询结果:<br>Iterator iterator = collection.iterator();<br>while(iterator.hasNext(){<br>Object current = iterator.next();<br>... use current...<br>}<br><br>下面,我们考虑接口设计的第二个原则:<br><br>组合方法(Combined Method)<br>组合方法经常在线程和分布环境中使用,来保证正确性并改善效率。<br><br>一些接口提供大量的方法,起初,这些方法看来是最小化的,而且相关性强。然而,在使用的过程中,一些<br>接口显现得过于原始,它们过于简单化,从而迫使类用户用更多的工作来实现普通的任务,并且,方法之间<br>的先后顺序及依赖性比较强(即,暂时耦合)。这导致了代码重复,而且非常麻烦和容易出错。<br><br>一些需要同时执行成功的方法,在多线程、异常、和分布的情况下会遇到麻烦。如果两个动作需要同时执<br>行,它们由两个独立的方法进行描述,必须都完全成功的执行,否则会导致所有动作的回滚。<br><br>线程的引入使这种不确定性大大增加。一系列方法同时调用一个易变的(mutable)对象,如果这个对象在线<br>程之间共享,即使我们假设单独的方法是线程安全的,也无法确保结果是意料之中的。看下面对Event<br>Source的接口,它允许安置句柄和对事件的查询:<br>interface EventSource{<br>Handler getHandler(Event event);<br>void installHandler(Event event, Handler newHandler);<br>}<br><br>线程之间的交叉调用可能会引起意想不到的结果。假设source域引用一个线程共享的对象,对象很可能在<br>1、2之间被另一个线程安装了一个新的句柄:<br>class EventSourceExample{<br>public void example(Event event, Handler newHandler){<br>oldHandler = eventSource.getHandler(event); // 1<br>//对象很可能在这里被另一个线程安装了一个新的句柄<br>eventSource.installHandler(event, newHandler); // 2<br>}<br>private EventSource eventSource;<br>private Handler oldHandler;<br>}<br><br>为了解决问题,也需要由类的使用者而不是类的设计者来完成:<br>class EventSourceExample{<br>public void example(Event event, Handler newHandler){<br>synchronized(eventSource){<br>oldHandler = eventSource.getHandler(event);<br>eventSource.installHandler(event, newHandler);<br>}<br>}<br>private EventSource eventSource;<br>private Handler oldHandler;<br>}<br><br>我们假设:目标对象eventSource是远程的,执行每一个方法体的时间和通讯的延迟相比是很短的。在这个<br>例子中,eventSource的方法被调用了两次,并可能在其他的实例中重复多次,因而,开销也是至少两倍。<br><br>此外还有一个问题是对外部的synchronized同步块的使用需求。对synchronized块的使用之所以会失败,主<br>要因为我们通过代理对象来完成工作,所以,调用者的synchronized块,同步的是代理对象而不是最终的目<br>标对象,调用者不可能对其行为做太多的保证。<br><br>Combined Method必须在分布的环境,或者,线程环境中同时执行。它反映了用户直接的应用,恢复策略和<br>一些笨拙的方法被封装到Combined Method中,并简化了接口,减少了接口中不需要的累赘。Combined<br>Method的效果是支持一种更像事务处理风格的设计。<br><br>在一个组合的Command-Query中提供一个单独的Query方法通常是合理的。提供分离的Command方法是不太常<br>见的,因为Combined Method可以完成这一工作,只要调用者简单的忽略返回结果。如果返回一个结果招致<br>一个开销的话,才可能会提供一个单独的Command方法。<br><br>回到前一个例子中,如果installHandler method返回上一次安装的句柄,则设计变得更加简单和独立:<br>interface EventSource{<br>Handler installHandler(Event event, Handler newHandler);<br>}<br><br>客户代码如下:<br>class EventSourceExample{<br>public void example(Event event, Handler newHandler){<br>oldHandler = eventSource.installHandler(event, newHandler);<br>}<br>private EventSource eventSource;<br>private Handler oldHandler;<br>}<br><br>这样,我们给调用者提供了一个更加安全的接口,并且不再需要他们解决线程的问题。从而降低了风险和代<br>码量,将类设计的职责全部给了类设计者而不是推给用户,即使有代理对象的出现也不会影响到正确性。<br><br>一个Combined Method可以是许多Query的集合,许多Command的集合,或者两者兼有。这样,它可能补充<br>Command、Query方法,也可能与之相抵触。当冲突发生的时候,优先选择Combined Method会产生一个不同<br>的正确性和适用性。<br><br>在另一个例子中,我们考虑获得资源的情况。假设,在下面的接口中,方法acquire在资源可用前阻塞:<br>interface Resource{<br>boolean isAcquired();<br>void acquire();<br>void release();<br>}<br><br>类似于下面的代码会在一个线程系统中推荐使用:<br>class ResourceExample{<br>public void example(){<br>boolean acquired = false;<br>synchronized(resource){<br>if(!resource.isAcquired())<br>resource.acquire();<br>else<br>acquired = true;<br>}<br>if(!acquired)<br>...<br>}<br>private Resource resource;<br>}<br><br>然而,即使我们放弃可读性和易用性,这样的设计也不是一个Command-Query分离的设计。如果引入了代<br>理,它就会失败:<br>class ActualResource implements Resource {...}<br>class ResourceProxy implements Resource {...}<br><br>如果用户既可以通过ActualResource来完成工作,也可以通过ResourceProxy来完成工作,而且,<br>ActualResource和ResourceProxy都没有处理同步,则synchronized块可能会失败。因为,既然我们可以通<br>过代理对象ResourceProxy来完成工作,那么,调用者的synchronized块,同步的就是代理对象<br>ResourceProxy而不是最终的目标对象ActualResource。<br><br>一个Combined Method解决了这个问题,它使并发和间接性更加透明。<br>interface Resource{<br>boolean tryAcquire();<br>}<br><br>下面的代码清晰、简单并且正确:<br>class ResourceExample{<br>public void example(){<br>if(!resource.tryAcquire())<br>...<br>}<br>private Resource resource;<br>}<br><br>Combined Method带来的一个结果是使一些测试和基于断言的程序设计变得十分笨拙,然而,它适合解决线<br>程和分布问题。<br><br>实际应用中,接口应该单一化还是复合化,要视具体情况而定。
L luoyanqing119 Unregistered / Unconfirmed GUEST, unregistred user! 2008-09-11 #4 也可以写一个跨数据库存取的动作就可以了.在ORACLE的JOBS上写一个定时执行的过程.这样就不一定要人工维护了.很爽的(ORA真的好强).