24种设计模式--桥梁模式【Bridge Pattern】
今天我要说说我自己,梦想中的我自己,我身价过亿,有两个大公司,一个是房地产公司,一个是服装制造业,这两个公司都很赚钱,天天帮我在累加财富,其实是什么公司我倒是不关心,我关心的是是不是在赚钱,赚了多少,我先用类图表示一下我这两个公司:
类图很简单,声明了一个 Corp 抽象类,定义一个公司的抽象模型,公司首先要是赚钱的,不赚钱谁开公司,做义务或善举那也是有背后利益支撑的,我还是赞这句话“天下熙熙,皆为利来;天下壤壤,皆为利往”,那我们先看 Corp 类的源代码:
package com.pattern.bridge; /**
* 定义一个公司的抽象类
* @author http://www.cnblogs.com/initial-road/
*
*/
public abstract class Corp { /**
* 是公司就应该有生产吧,甭管是什么软件公司还是制造业公司
* 那每个公司生产的东西都不一样,所以由实现类来完成
*/
protected abstract void produce(); /**
* 有产品了,那肯定要销售呀,不销售你公司怎么生存
*/
protected abstract void sell(); /**
* 公司是干什么的?赚钱的
*/
protected void makeMoney(){ //每个公司都是一样,先生产
this.produce(); //然后销售
this.sell(); } }
合适的方法存在合适的类中,这个基本上是每本 Java 基础书上都会讲的,但是到实际的项目中应用的时候就不是这么回事儿了,正常的很。我们继续看两个实现类如何实现的,先看 HouseCorp 类,这个是我最赚钱的公司:
package com.pattern.bridge; /**
* 房地产公司,按照翻译来说应该叫realty corp,这个是比较准确的翻译
* 但是我问你房地产公司翻译成英文,你第一反应是什么?对嘛还是house corp
* @author http://www.cnblogs.com/initial-road/
*
*/
public class HouseCorp extends Corp { // 房地产公司就是盖房子
protected void produce() {
System.out.println("房地产公司盖房子...");
} // 房地产卖房子,自己住那可不赚钱
protected void sell() {
System.out.println("房地产公司出售房子...");
} // 房地产公司很High了,赚钱,计算利润
public void makeMoney(){
super.makeMoney();
System.out.println("房地产公司赚大钱了...");
} } 然后看服装公司,虽然不景气,但好歹也是赚钱的: package com.pattern.bridge; /**
* 服装公司,这个行当现在不怎么样
* @author http://www.cnblogs.com/initial-road/
*
*/
public class ClothesCorp extends Corp { // 服装公司生成的就是衣服了
protected void produce() {
System.out.println("服装公司生产衣服...");
} // 服装公司做服装,可只卖服装,不买穿衣服的模特
protected void sell() {
System.out.println("服装公司出售衣服...");
} // 服装公司不景气,但怎么说也是赚钱行业耶
public void makeMoney(){
super.makeMoney();
System.out.println("服装公司赚小钱...");
} }
两个公司都有了,那肯定有人会关心两个公司的运营情况呀,我自己怎么也要知道它是生产什么的,赚多少钱吧,那看看这个 Client.java 是什么样子的:
package com.pattern.bridge; /**
* 我要关心我自己的公司了
* @author http://www.cnblogs.com/initial-road/
*
*/
public class Client { public static void main2(String[] args) {
System.out.println("------房地产公司是这个样子运行的------");
// 先找到我的公司
HouseCorp houseCorp = new HouseCorp();
// 看我怎么挣钱
houseCorp.makeMoney();
System.out.println("\n"); System.out.println("------服装公司是这样运行的------");
ClothesCorp clothesCorp = new ClothesCorp();
clothesCorp.makeMoney();
} }
上述代码完全可以描述我现在的公司,但是你要知道万物都是运动的,你要用运动的眼光看问题,我公司也会发展,终于在有一天我觉得赚钱速度太慢,于是我上下疏通,左右打关系,终于开辟了一条赚钱的康庄大道:生产山寨产品,什么产品呢?就是市场上什么牌子的东西火爆我生产什么牌子的东西,甭管是打火机还是电脑,只要它火爆,我就生产,赚过了高峰期就换个产品,打一枪换一个牌子,不承担售后成本、也不担心销路问题,我只有正品的十分之一的价格,你买不买?哈哈,赚钱呀!
企业的方向定下来了,通过调查,市场上前段时间比较火爆的是苹果 iPod,那咱就生产这个,把服装厂该成 iPod 生产厂,看类图的变化:
好,我的企业改头换面了,开始生产 iPod 产品了,看我 IPodCorp 类的实现:
package com.pattern.bridge; /**
* 我是山寨老大,你流行啥我生产啥
* 现在流行ipod
* @author http://www.cnblogs.com/initial-road/
*
*/
public class IPodCorp extends Corp { // 我开始生产iPod了
protected void produce() {
System.out.println("我生产iPod...");
} // 山寨的iPod很畅销,便宜呀
protected void sell() {
System.out.println("iPod畅销...");
} public void makeMoney(){
super.makeMoney();
System.out.println("我赚钱呀...");
} } 这个厂子修改完毕了,我这个董事长还要去看看到底生产什么的,看这个 Client.java 程序: package com.pattern.bridge; /**
* 我要关心我自己的公司了
* @author http://www.cnblogs.com/initial-road/
*
*/
public class Client { public static void main2(String[] args) {
System.out.println("------房地产公司是这个样子运行的------");
// 先找到我的公司
HouseCorp houseCorp = new HouseCorp();
// 看我怎么挣钱
houseCorp.makeMoney();
System.out.println("\n"); System.out.println("------山寨公司是这样运行的------");
IPodCorp iPodCorp = new IPodCorp();
iPodCorp.makeMoney();
} }
确实,只用修改了几句话,我的服装厂就开始变成山寨 iPod 生产车间,然后就看我的财富在积累,你想呀山寨的东西不需要特别的销售渠道,不需要维修成本,不承担广告成本,但是我也有犯愁的时候,我这是个山寨工厂,要及时的生产出市场上流行产品,转型要快,要灵活,今天从生产 iPod转为生产MP4, 明天再转为生产上网本,这个都需要灵活的变化,不要限制的太死,那问题来了,每次我的厂房,我的工人,我的设备都在,不可能每次我换个山寨产品我的厂子就彻底不要了,这不行,成本忒高了点,那怎么办?
这样设计:
Corp 类和 Product 类建立一个关联关系,可以彻底解决我以后山寨公司生产产品的问题,看程序说话,先看 Product 抽象类:
package com.pattern.bridge.implementor; /**
* 这是我整个集团公司的产品类
* @author http://www.cnblogs.com/initial-road/
*
*/
public abstract class Product { //甭管是什么产品它总要是能被生产出来
public abstract void beProducted(); // 生产出来的东西,一定要销售出去,否则亏本呀
public abstract void beSelled(); } 简单,忒简单了,看 House 产品类: package com.pattern.bridge.implementor; /**
* 这是我集团公司盖的房子
* @author http://www.cnblogs.com/initial-road/
*
*/
public class House extends Product { // 豆腐渣就豆腐渣呗,好歹也是个房子
public void beProducted() {
System.out.println("生产出的房子是这个样子的...");
} // 虽然是豆腐渣,也是能够销售出去的
public void beSelled() {
System.out.println("生产出的房子卖出去了...");
} } 不多说,看 Clothes 产品类: package com.pattern.bridge.implementor; /**
* 我集团公司生产的衣服
* @author http://www.cnblogs.com/initial-road/
*
*/
public class Clothes extends Product { public void beProducted() {
System.out.println("生产出的衣服是这个样子的...");
} public void beSelled() {
System.out.println("生产出的衣服卖出去了...");
} } 下面是 iPod 产品类: package com.pattern.bridge.implementor; /**
* 生产iPod了
* @author http://www.cnblogs.com/initial-road/
*
*/
public class IPod extends Product { public void beProducted() {
System.out.println("生产出的iPod是这个样子的...");
} public void beSelled() {
System.out.println("生产出的iPod卖出去了...");
} }
产品类是有了,那我们再看 Corp 抽象类:
package com.pattern.bridge.abstraction; import com.pattern.bridge.implementor.Product; /**
* 定义一个公司的抽象类
* @author http://www.cnblogs.com/initial-road/
*
*/
public abstract class Corp { // 定义一个产品对象, 抽象的了,不知道具体是什么产品
private Product product; // 构造函数,由子类定义传递具体的产品进来
public Corp(Product product){
this.product = product;
} // 公司是干什么的?赚钱的呀
public void makeMoney(){ // 每个公司都是一样,先生产
this.product.beProducted(); // 然后销售
this.product.beSelled(); } }
这里多了个有参构造,其目的是要继承的子类都必选重写自己的有参构造函数,把产品类传递进来,再看子类 HouseCorp 的实现:
package com.pattern.bridge.abstraction; import com.pattern.bridge.implementor.House; /**
* 房地产公司,按照翻译来说应该叫realty corp,这个是比较准确的翻译
* 但是我问你房地产公司翻译成英文,你第一反应什么?对吗还是house corp!
* @author http://www.cnblogs.com/initial-road/
*
*/
public class HouseCorp extends Corp { // 定义传递一个House产品进来
public HouseCorp(House house) {
super(house);
} // 房地产公司很High了,赚钱,计算利润
protected void produce() {
super.makeMoney();
System.out.println("房地产公司赚大钱了...");
} protected void sell() {
System.out.println("销售房子了...");
} } 理解上没有多少难度,不多说,继续看山寨公司的实现: package com.pattern.bridge.abstraction; import com.pattern.bridge.implementor.Product; /**
* 我是山寨老大,你流行啥我就生产啥
* @author http://www.cnblogs.com/initial-road/
*
*/
public class ShanZhaiCorp extends Corp { // 产什么产品,不知道,等被调用了才知道
public ShanZhaiCorp(Product product) {
super(product);
} // 狂赚钱
public void makeMoney(){
super.makeMoney();
System.out.println("我赚钱呀...");
}
}
HouseCorp 类和 ShanZhaiCorp 类的区别是在有参构造的参数类型上, HouseCorp 类比较明确,我就是只要 House 类,所以直接定义传递进来的必须是 House 类, 一个类尽可能少的承担职责,那方法也是一样,既然 HouseCorp 类已经非常明确只生产 House 产品,那为什么不定义成 House 类型呢?ShanZhaiCorp 就不同了,它是确定不了生产什么类型。
好了,两大对应的阵营都已经产生了,那我们再看 Client 程序:
package com.pattern.bridge.abstraction; import com.pattern.bridge.implementor.House;
import com.pattern.bridge.implementor.IPod; /**
* 我要关心我自己的公司了
* @author http://www.cnblogs.com/initial-road/
*
*/
public class Client { public static void main(String[] args) {
House house = new House();
System.out.println("-----房地产公司是这个样子运行的-----");
// 先找到我的公司
HouseCorp houseCorp = new HouseCorp(house);
// 看我怎么挣钱
houseCorp.makeMoney();
System.out.println("\n"); // 山寨公司生产的产品很多,不过我只要制定的产品就成了
System.out.println("-----山寨公司是这样子运行的-----");
ShanZhaiCorp shanZhaiCorp = new ShanZhaiCorp(new IPod());
shanZhaiCorp.makeMoney();
} } 这个山寨公司的前身是生产衣服的,那我现在要修改一下,生产 iPod,看如下的变化: package com.pattern.bridge.abstraction; import com.pattern.bridge.implementor.House;
import com.pattern.bridge.implementor.IPod; /**
* 我要关心我自己的公司了
* @author http://www.cnblogs.com/initial-road/
*
*/
public class Client { public static void main(String[] args) {
House house = new House();
System.out.println("-----房地产公司是这个样子运行的-----");
// 先找到我的公司
HouseCorp houseCorp = new HouseCorp(house);
// 看我怎么挣钱
houseCorp.makeMoney();
System.out.println("\n"); // 山寨公司生产的产品很多,不过我只要制定的产品就成了
System.out.println("-----山寨公司是这样子运行的-----");
// ShanZhaiCorp shanZhaiCorp = new ShanZhaiCorp(new Clothes());
ShanZhaiCorp shanZhaiCorp = new ShanZhaiCorp(new IPod());
shanZhaiCorp.makeMoney();
} }
看代码上注释的一行代码,就修改了这一句代码就完成了生产产品的转换。那我们深入的思考一下,既然万物都是运动的,我现在只有房地产公司和山寨公司,那以后我会不会增加一些其他的公司呢?或者房地产公司会不会对业务进行细化,比如分为公寓房公司,别墅公司,以及商业房公司等等呢?那我告诉你,会的,绝对的会的,但是你发觉没,这种变化对我们上面的类图没有大的修改,充其量是扩展,你看呀:
增加公司,你要么继承 Corp 类,要么继承 HouseCorp 或 ShanZhaiCorp,不用再修改原有的类了;增加产品,继承 Product 类,或者继承 House类,你要把房子分为公寓住房、别墅、商业用房等等;你都是在扩展,唯一你要修改的就是 Client 类,你类都增加了哪能不修改调用呢,也就是说 Corp 类和 Product 类都可以自由的扩展,而不会对整个用产生太的变更,这就是桥梁模式。
为什么叫桥梁模式?我们看一下桥梁模式的通用类图:
看到中间那根带箭头的线了吗?是不是类似一个桥,连接了两个类?所以就叫桥梁模式。我们再把桥梁模式的几个概念熟悉一下,大家有没有注意到我把 Corp 类以及它的两个实现类放到了 Abstraction 包中,把 House以及相关的三个实现类放到了 Implementor 包中,这两个包分别对应了桥梁模式的业务抽象角(Abstraction)和业务实现角色(Implementor),这两个角色我估计没几个人能说的明白,特别是看了“四人帮”的书或者是那本非常有名的、比砖头还要厚的书,你会越看越糊涂,忒专业化,有点像看政府的红头文件,什么都说了,可好像又什么都没有说。这两个角色大家只要记住一句话就成:业务抽象角色引用业务实现角色,或者说业务抽象角色的部分实现是由业务实现角色完成的,很简单,别想那么复杂了。
桥梁模式的优点就是类间解耦,我们上面已经提到,两个角色都可以自己的扩展下去,不会相互影响,这个也符合 OCP 原则。
今天说到桥梁模式,那就多扯几句,大家对类的继承有什么看法吗?继承的优点有很多,可以把公共的方法或属性抽取,父类封装共性,子类实现特性,这是继承的基本功能,缺点有没有?有,强关联关系,父类有个方法,你子类也必须有这个方法,是不可选择的,那这会带来扩展性的问题,我举个简单的例子来说明这个问题:Father 类有一个方法A, Son 继承了这个方法,然后GrandSon 也继承了这个方法,问题是突然有一天Son要重写父类的这个方法,他敢做吗?绝对不敢! GrandSon 可是要用从Father 继承过来的方法A,你修改了,那就要修改Son 和GrandSon 之间的关系,那这个风险就大了去。
今天讲的这个桥梁模式就是这一问题的解决方法,桥梁模式描述了类间弱关联关系,还说上面的那个例子,Fater 类完全可以把可能会变化的方法放出去, Son 子类要有这个方法很简单,桥梁搭过去,获得这个方法,GrandSon 也一样,即使你Son 子类不想使用这个方法了,也没关系,对GrandSon 不产生影响,他不是从你Son 中继承来的方法!
继承不能说它不好,非常好,但是有缺点的,我们可以扬长避短,对于比较明确不发生变化的,则通过继承来完成,若不能确定是否会发生变化的,那就认为是会发生变化,则通过桥梁模式来解决,这才是一个完美的世界。
24种设计模式--桥梁模式【Bridge Pattern】的更多相关文章
- 24种设计模式-策略模式(Strategy Pattern)
一.优点: 1. 策略模式提供了管理相关的算法族的办法.策略类的等级结构定义了一个算法或行为族.恰当使用继承可以把公共的代码转移到父类里面,从而避免重复的代码. 2. 策略模式提供了可以替换继承关系的 ...
- 说说设计模式~桥梁模式(Bridge)
返回目录 在软件系统中,某些类型由于自身的逻辑,它具有两个或多个维度的变化,那么如何应对这种“多维度的变化”?如何利用面向对象的技术来使得该类型能够轻松的沿着多个方向进行变化,而又不引入额外的复杂度? ...
- 转:设计模式-----桥接模式(Bridge Pattern)
转自:http://www.cnblogs.com/houleixx/archive/2008/02/23/1078877.html 记得看原始链接的评论. 学习设计模式也有一段时间了,今天就把我整理 ...
- 变脸不变质的桥梁模式(Bridge Pattern)
有一哥们是搞山寨货的,什么流行就搞什么.自己有个厂子,前些时间服装挣钱,就生产衣服,如今搞手机挣钱,搞手机,这哥们非常聪明,就换了个产品,工人,厂房都不变.他是怎么做到的?用类图来模拟一下: 由类图能 ...
- 桥梁模式(Bridge Pattern)
桥梁模式是对象的结构模式.又称为柄体(Handle and Body)模式或接口(Interface)模式.桥梁模式的用意是“将抽象化(Abstraction)与实现化(Implementation) ...
- 24种设计模式--迭代模式【Iterator Pattern】
周五下午,我正在看技术网站,第六感官发觉有人在身后,扭头一看,我 C,老大站在背后,赶忙站起来,“王经理,你找我?” 我说. “哦,在看技术呀.有个事情找你谈一下,你到我办公室来一下.” 老大说. 到 ...
- 24种设计模式--访问者模式【Visitor Pattern】
今天天气不错,绝对是晴空万里,骄阳似火呀,好,我们今天来讲访问者模式,我们在前面讲了组合模式和迭代器模式,通过组合模式我们能够把一个公司的人员组织机构树搭建起来,给管理带来非常大的便利,通过迭代器模式 ...
- 24种设计模式--原型模式【Prototype Pattern】
今天我们来讲原型模式,这个模式的简单程度是仅次于单例模式和迭代器模式,非常简单,但是要使用好这个模式还有很多注意事项.我们通过一个例子来解释一下什么是原型模式. 现在电子账单越来越流行了,比如你的信用 ...
- 24种设计模式--组合模式【Composite Pattern】
大家在上学的时候应该都学过“数据结构”这门课程吧,还记得其中有一节叫“二叉树”吧,我们上学那会儿这一章节是必考内容,左子树,右子树,什么先序遍历后序遍历什么,重点就是二叉树的的遍历,我还记得当时老师就 ...
随机推荐
- 门面模式 到 socket
http://www.cnblogs.com/java-my-life/archive/2012/05/02/2478101.html 1.门面模式定义: 门面模式是对象的结构模式,外部与一个子系统的 ...
- ElasticSearch elasticsearch-servicewrapper 在linux上的安装部署全程记录
原文地址:http://www.cnblogs.com/tianjixiaoying/p/4316011.html 由于项目需求,需要在linux平台搭建一套ES服务.在搭建过程中,遇到各种各样的问题 ...
- 排列的Java递归语言实现
在做算法题的时候,发现排列经常被使用到,是一个重要的知识点, 下面是博主修改过的代码,初学者,如有不足,欢迎指出 import java.util.ArrayList; import java.uti ...
- 系统内存和CPU管理、监控
本博文的主要内容有 .系统内存管理.监控:vmstat和free -mt .系统CPU管理.监控:sar -u.mpstat.uptime linux系统内存和CPU是在系统运行的过程中不断消耗的资源 ...
- 在CentOS搭建Git服务器 转
在CentOS搭建Git服务器 来自 :http://www.jianshu.com/p/69ea5ded3ede 前言 我们可以GitHub发布一些开源代码的公共仓库,但对于私密仓库就需要收费了.公 ...
- Yii 设置 flash消息 创建一个渐隐形式的消息框
/*适用情况:比如提交一个表单,提交完成之后在页面展示一条提示消息. 控制器里面这样写: 单条消息: */ \Yii::$app->getSession()->setFlash('erro ...
- Redis实战之Redis + Jedis[转]
http://blog.csdn.net/it_man/article/details/9730605 2013-08-03 11:01 1786人阅读 评论(0) 收藏 举报 目录(?)[-] ...
- Android实战技巧之六:PreferenceActivity使用详解
一.写作前面 当我们做应用的时候,需要用户配置一些信息,而这就是通常所说的应用设置. 对于Android系统来说,系统本身的设置带来的用户体验和习惯已经深入人心,在我们的应用中同样用到类似的设置页, ...
- Qss All
/* * OOMidi application style sheet */QFrame#transportToolButtons{border: 0;spacing: 0;margin: 0;pad ...
- 安卓Intent(显式)
1.Intent是Android程序中各组件之间交互的重要方式,一般可用于启动活动.启动服务.以及发送广播等场景,这里先对活动进行说明Intent的一些作用. 2.Intent的用法大致可分为,显式I ...