LoveUnix » 行业应用 项目实施 » 从重构的角度学习bridge设计模式
让LU留住您的每

一天 让LU博客留住您的每一天
2003-11-12 00:46 无双
从重构的角度学习bridge设计模式<br /><br />Bridge模式是一个在实际系统中经常应用的模式。它最能体现设计模式的原则<br />针对接口进行编程,和使用聚合不使用继承这两个原则。<br /><br /><br />由于我们过分的使用继承,使类的结构过于复杂,不易理解,难以维护。特别<br />是在Java中由于不能同时继承多个类,这样就会造成多层继承,维护更难。<br />Bridge模式是解决多层继承的根本原因。如果你在实现应用中一个类,需要继承<br />两个以上的类,并且这两者之间又持有某种关系,它们两个都会有多种变化。<br />Bridge模式是把这两个类,分解为一个抽象,一个实现,使它们两个分离,这样<br />两种类可以独立的变化。<br />抽象就是,把一个实体的共同概念(相同的步骤),抽取出来(分解出几个相互独立的步骤),<br />作为一个过程。如我们把数据库的 操作抽象为一个过程,有几个步骤,创建SQL语句,<br />发送到数据库处理,取得结果。<br /><br />实现就是怎样完成这个抽象步骤,如发送到数据库,需要结合具体的数据库,考虑怎样完成这个步骤等。<br />并且同一步骤可能存在不同的实现,如对不同的数据库需要不同的实现。<br /><br />现在我们假设一个情况,也是WEB中经常遇到的,在一个page有输入框,<br />如客户信息的姓名,地址等,输入信息后,然后按查找按钮,把查找的结果显示出来。<br />我们现在假设查找客户信息和帐户信息,它们在不同的表中。<br />但是我们的系统面对两种人群,总部的它们信息保存到oracle数据库,但是各个分公司<br />的数据保存在Sybase中,数据库的位置等各不相同,这两种的操作不同。<br /><br />下面是我们一般首先会使用的方式,使用if else进行,判断,这样使用系统<br />难以维护,难以扩展,不妨你增加一种查询,或者一种数据库试试????<br /><!--c1--><div class='codetop'>CODE</div><div class='codemain'><!--ec1--><br />public class SearchAction&#40;&#41;{ <br /> &nbsp; &nbsp;public Vector searchData&#40;string ActionType,String DbType&#41;{<br /> &nbsp; &nbsp; &nbsp; &nbsp;String SQL=&#34;&#34;; <br /> &nbsp; &nbsp; &nbsp; &nbsp;if&#40;ActionType.equal&#40;&#34;查找客户信息&#34;&#41;&#41;{<br /> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;//如果是查询客户信息,拼SQL语句从客户表中读取数据<br /> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;SQL=&#34;select * from Customer &#34;<br /><br /> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;if&#40;dbType.equal&#40;&#34;oracle&#34;&#41;&#41;{<br /> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;//从总部数据库读取,数据库为Oracle<br /> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;String connect_string =&#34;jdbc&#58;oracle&#58;thin&#58;hr/hr@localhost&#58;1521&#58;HRDB&#34;;<br /> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;DriverManager.registerDriver &#40;new oracle.jdbc.OracleDriver&#40;&#41;&#41;; <br /> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;Connection conn = DriverManager.getConnection &#40;connect_string&#41;;<br /> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;// Create a statement<br /> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;Statement stmt = conn.createStatement &#40;&#41;;<br /> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;ResultSet rset = stmt.executeQuery &#40;SQL&#41;;<br /> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;//以下省略部分动态从数据库中取出数据,组装成Vector,返回<br /> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;..................................<br /> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;................................... <br /> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;}else&#40;dbType.equal&#40;&#34;sybase&#34;&#41;&#41;{<br /> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;//从分公司数据库读取,数据库为Sybase<br /> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;String connect_string =&#34;jdbc&#58;sybase&#58;Tds&#58;cai/cai@192.168.1.12&#58;1521&#58;FIN&#34;;<br /> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;DriverManager.registerDriver &#40;new com.sybase.jdbc.SybDriver&#40;&#41;&#41;; <br /> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;Connection conn = DriverManager.getConnection &#40;connect_string&#41;;<br /> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;// Create a statement<br /> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;Statement stmt = conn.createStatement &#40;&#41;;<br /> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;ResultSet rset = stmt.executeQuery &#40;SQL&#41;;<br /> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;//以下省略部分动态从数据库中取出数据,组装成Vector,返回<br /> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;..................................<br /> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;...................................<br /><br /> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;} <br /><br /> &nbsp; &nbsp; &nbsp; &nbsp;}else if&#40;ActionType.equal&#40;&#34;查找帐户信息&#34;&#41;&#41;{<br /> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;//如果是查询帐户信息,拼接SQL语句从帐户表中读取数据<br /> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;SQL=&#34;select * from Account &#34;<br /> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;if&#40;dbType.equal&#40;&#34;oracle&#34;&#41;&#41;{<br /> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;..........................<br /> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;..........................<br /> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&#40;作者注:此处省略从oracle读取,约300字&#41;<br /><br /> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;}else if&#40;dbType.equal&#40;&#34;Sybase&#34;&#41;&#41;{<br /> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;..........................<br /> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;..........................<br /> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&#40;作者注:此处省略从Sybase读取,约300字&#41; <br /> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;} <br /><br /> &nbsp; &nbsp; &nbsp; &nbsp;} <br /> &nbsp; &nbsp;}<br />}<br /><!--c2--></div><!--ec2--><br /><br />如果你认为这写的比较弱智,应该进行使用函数,但是你也会大量使用if else.???<br /><br />于是我们进行重构,首先我们学习过DAO模式,就是把数据读取进行分里,我们定义一个<br />共同的接口,它负责数据库的操作,然后根据不同的数据库进行实现,在我们的查询操作中,<br />使用接口,进行操作,这样就可以不用考虑具体的实现,我们只管实现过程。<br /><!--c1--><div class='codetop'>CODE</div><div class='codemain'><!--ec1--><br />查询共同接口: <br /> &nbsp; &nbsp;public interface searchDB{<br /> &nbsp; &nbsp; &nbsp; &nbsp;public Vector searchFromDB&#40;String SQL&#41;<br /> &nbsp; &nbsp;}<br />Oracle数据库的查询实现<br />public class searchDBOracleImpl{<br /> &nbsp; &nbsp;public Vector searchFromDB&#40;String SQL&#41;{<br /> &nbsp; &nbsp; &nbsp; &nbsp;//从总部数据库读取,数据库为Oracle<br /> &nbsp; &nbsp; &nbsp; &nbsp;String connect_string =&#34;jdbc&#58;oracle&#58;thin&#58;hr/hr@localhost&#58;1521&#58;HRDB&#34;;<br /> &nbsp; &nbsp; &nbsp; &nbsp;DriverManager.registerDriver &#40;new oracle.jdbc.OracleDriver&#40;&#41;&#41;; <br /><br /> &nbsp; &nbsp; &nbsp; &nbsp;ResultSet rset = stmt.executeQuery &#40;SQL&#41;;<br /> &nbsp; &nbsp; &nbsp; &nbsp;.............................<br /> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;............................<br /><br /> &nbsp; &nbsp;}<br />}<br />Sybase数据库的查询实现 <br />public class searchDBSysbaseImpl{<br /> &nbsp; &nbsp;public Vector searchFromDB&#40;String SQL&#41;{<br /> &nbsp; &nbsp; &nbsp; &nbsp;//从分公司数据库读取,数据库为Sysbase<br /> &nbsp; &nbsp; &nbsp; &nbsp;String connect_string =&#34;jdbc&#58;sybase&#58;Tds&#58;cai/cai@192.168.1.12&#58;1521&#58;FIN&#34;;<br /> &nbsp; &nbsp; &nbsp; &nbsp;DriverManager.registerDriver &#40;new com.sybase.jdbc.SybDriver&#40;&#41;&#41;; <br /> &nbsp; &nbsp; &nbsp; &nbsp;ResultSet rset = stmt.executeQuery &#40;SQL&#41;;<br /> &nbsp; &nbsp; &nbsp; &nbsp;.............................<br /> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;............................<br /><br /> &nbsp; &nbsp;}<br />} <br /><!--c2--></div><!--ec2--><br /><br />这样在我们的查询中就可以使用接口searchDB,但是创建有是一个问题,因为我们不能<br />静态的确定,查询的数据库类型,必须动态确定,于是我们又想到使用简单工厂方法,<br />来分别创建这里的具体实现,根据类别,创建<br /><!--c1--><div class='codetop'>CODE</div><div class='codemain'><!--ec1--><br />public class searchFactory{<br /> &nbsp; &nbsp;public static searchDB createSearch&#40;int DBType&#41;{<br /> &nbsp; &nbsp; &nbsp; &nbsp;if&#40;DBType.equal&#40;&#34;oracle&#34;&#41;&#41;{<br /> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;return searchDBOracleImpl&#40;&#41;;<br /> &nbsp; &nbsp; &nbsp; &nbsp;}else if&#40;DBType.equal&#40;&#34;sybase&#34;&#41;&#41;{<br /> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;return searchDBSysbaseImpl&#40;&#41;;<br /> &nbsp; &nbsp; &nbsp; &nbsp;}<br /> &nbsp; &nbsp;}<br />}<!--c2--></div><!--ec2--><br />于是我们的查询代码可以改变为这样了;<br /><!--c1--><div class='codetop'>CODE</div><div class='codemain'><!--ec1--><br />public class SearchAction&#40;&#41;{<br /><br /> &nbsp; &nbsp;public Vector searchData&#40;string ActionType,String DbType&#41;{<br /> &nbsp; &nbsp; &nbsp; &nbsp;String SQL=&#34;&#34;; <br /> &nbsp; &nbsp; &nbsp; &nbsp;if&#40;ActionType.equal&#40;&#34;查找客户信息&#34;&#41;&#41;{<br /> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;//如果是查询客户信息,拼SQL语句从客户表中读取数据<br /> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;SQL=&#34;select * from Customer &#34; <br /> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;searchDB obj=searchFactory.createSearch&#40;DbType&#41;;<br /> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;return obj.searchFromDB&#40;SQL&#41;;<br /><br /> &nbsp; &nbsp; &nbsp; &nbsp;}else if&#40;ActionType.equal&#40;&#34;查找帐户信息&#34;&#41;&#41;{<br /> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;//如果是查询帐户信息,拼接SQL语句从帐户表中读取数据<br /> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;SQL=&#34;select * from Account &#34;<br /> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;searchDB obj=searchFactory.createSearch&#40;DbType&#41;;<br /> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;return obj.searchFromDB&#40;SQL&#41;; <br /> &nbsp; &nbsp; &nbsp; &nbsp;} <br /> &nbsp; &nbsp;}<br />}<!--c2--></div><!--ec2--><br /><br />是不是简单一些,如果增加一个新的数据库,对我们只需增加一个新的数据库实现便可,<br />老的代码,不需改变,这样便实现开-闭原则(Open-closed原则),在我们的查询查询<br />中使用的是接口,这就是设计模式的原则,针对接口进行编程,并且使用聚合,而不是直接的继承<br />大家,可以考虑使用继承来完成该工作怎样实现?????<br /><br />上面是把实现进行分离,实现可以动态变化!!!!!<br /><br />我们把查询的操作的具体数据库实现进行了分离,增强了灵活性,但是我们的查询。<br />仍然使用了if else这样仍然不易进行扩展,于是我们进行抽象一个查询操作的过程,<br />把它分成几个具体步骤,创建SQL语句,发送到数据库,执行查询,返回结果。<br />它们虽然是不同的查询,SQL各不相同,不同数据库执行不同,返回结果的内容不同。但是<br />这个过程却是不变的,于是我们声明一个抽象类,来完成这个过程。<br /><br />public abstract class searchAction{<br />searchDB obj;<br />//两个步骤 <br />public searchDB createSearchImple(int DbType){<br />return searchFactory.createSearch(DbType);<br />}<br />public abstract String createSQL();<br /><br />//查询过程,最后返回结果<br />public vector searchResult(int DbType){<br />obj=createSearchImple(DbType);<br />return obj.searchFromDB(createSQL())<br />} <br />}<br /><br />//我们客户查询,操作<br />public class searchCustomerAction{ <br />public String createSQL(){<br />return &quot;select * from Customer&quot;<br />} <br />}<br />//我们的帐户查询操作<br />public class searchAccountAction{ <br />public String createSQL(){<br />return &quot;select * from account&quot;<br />} <br />}<br /><br />这样我们的查询编程简单的创建SQL语句,我们应该再创建一个工厂方法,<br />来完成创建它们<br />public class actionFactory{<br />public static searchAction ceateAction(int actionType){<br />if(actionType.equal(&quot;customer&quot;)){<br />return searchCustomerAction();<br />}else if(actionType.equal(&quot;account&quot;)){<br />return searchAccountAction();<br />}<br />}<br />}<br />这样我们把查询操作的过程进行了抽象,定义了步骤,和具体过程,经过我们的两次改变<br />把抽象部分和实现部分进行分离,使他们都可以独立的变化,增强灵活性。<br />我们再看当初查询实现,现在经过这两次的地修改,变成了什么模样?如下:<br /><br />public class SearchAction(){ <br />public Vector searchData(string ActionType,String DbType){<br />searchAction action=actionFactory.ceateAction(ActionType);<br />return action.searchResult(DbType);<br />}<br />现在假如增加一个数据库类型,将会改变那些??,如果增加一种查询操作需要改变那些???<br /><br />讨论点:<br />1:在我们的重构过程中,<br />怎样使用设计模式原则的???<br />现在如果增加功能,遵循开闭原则吗??<br />2:我们使用了两个简单工厂,这是为了简化,一般最好使用抽象工厂方法,<br />如果改为抽象工厂,怎样修改???<br /><br /><br /><br />我打算写一系列的文章介绍设计模式,<br />希望从重构的角度考虑模式的应用,而不是<br />直接介绍模式,这样对初学者容易入门,step by step。<br />如果在自己的代码中遇到类似的情景,可以进行重构。<br /><br /><br />从重构学习proxy,预告<br />为什么EJB有Home,remote,bean这三种角色?<br />为什么又客户端与容器进行交互??<br />介绍在EJB中的应用???<br /><br />从重构学习decorator??

2003-11-12 10:52 大菠萝
无双这个例子不错,我觉得bridge就是当两组类,要将其联系起来而不暴露其的实现,通过分别对这两组类定义两个抽象类,通过定义这两个抽象类的联系从而达到不暴露这两组类而达到使他们联系起来,呵呵,这俩个抽象类就构成了一个桥,我想这就使bridge模式的名称的含义吧

2003-11-12 11:04 无双
我也这样理解的

2003-11-12 17:39 qinxj
先copy回去研究之后再来发言,呵呵!

2003-11-12 22:36 瓜小南
不错,双双贴的都是精品啊

2003-11-13 09:18 qinxj
仔细研究了一下,无双的作品的确是精品,易于理解,比我看&lt;&lt;模式设计&gt;&gt;上讲的还要容易理解!<br /><br />鼓励,支持,期待!

2003-11-13 10:29 无双
这也是其它网站上转过来的<br /><br />我觉得他写的好 而且清楚就转过来了

2003-11-13 10:35 qinxj
总之就是好,受益非浅,感谢感谢!<br /><br />建议加精吧!

页: [1]


Powered by Discuz! Archiver 5.5.0  © 2001-2006 Comsenz Inc.