设计模式(七)——桥接模式

179 阅读6分钟

上一篇:设计模式(六)——适配器模式

下一篇:设计模式(八)——代理模式

一、需求

官方解释: Decouple an abstraction from its implementation so that the two can vary independently.(将抽象和实现解耦,使得两者可以独立的变化。)

我的理解1: 人有灵魂和肉体,灵魂和肉体是一种相互依存的组合关系,不是父子继承关系

我的理解2: 最简单的理解桥接模式的方式便是像中学数学里面的坐标系一样,有两个维度 x轴和y轴。第一,二维坐标系上的任何一个点都同时拥有x坐标和y坐标;第二,只有确定了x坐标和y坐标,才能在坐标系上画出一个确定的点

参与者: Abstraction(抽象类)、RefinedAbstraction(具体抽象类)、Implementor(实现类)、ConcreteImplementor(具体实现类)

类图:

二、代码

代码1——灵魂肉体例子:

package mypackage;

public class DesignPatternDemo {

	public static void main(String[] args) {

		Body body = new FootBall_Game("foot", new Playing_FootBall());
		body.sport();
		body = new BasketBall_Game("hand", new Playing_BasketBall());
		body.sport();
	}

}

// 灵魂和肉体是两个不同的维度 不是父子继承关系 但是要组合在一起才能共同完成事情
interface Soul {
	public void sport();
}

// 灵魂要参与运动 但是仅仅灵魂这一个维度没有办法去实现参与运动 比如 踢足球需要脚 打篮球需要手 但是手脚是属于肉体 所以必须把灵魂注入肉体中
class Playing_FootBall implements Soul {

	@Override
	public void sport() {
		System.out.println("playing football");
	}

}

class Playing_BasketBall implements Soul {

	@Override
	public void sport() {
		System.out.println("playing basketball");
	}

}

// 同样 仅仅肉体这一个维度也没有办法完成踢足球和打篮球的运动 因为肉体只有手脚 没有思想 不知道要具体参与什么运动
abstract class Body {
	protected String organ;
	Soul soul;

	public Body(Soul soul) {
		this.soul = soul;
	}

	abstract void sport();

}

class FootBall_Game extends Body {

	public FootBall_Game(String organ, Soul soul) {
		super(soul);
		this.organ = organ;

	}

	@Override
	void sport() {
		soul.sport();
	}

}

class BasketBall_Game extends Body {

	public BasketBall_Game(String organ, Soul soul) {
		super(soul);
		this.organ = organ;
	}

	@Override
	void sport() {
		soul.sport();
	}

}

输出1:

playing football
playing basketball

扩展起来也是相当方便的,比如要加上要给打排球的运动

代码2——灵魂肉体例子扩展:

package mypackage;

public class DesignPatternDemo {

	public static void main(String[] args) {

		Body body = new FootBall_Game("foot", new Playing_FootBall());
		body.sport();
		body = new BasketBall_Game("hand", new Playing_BasketBall());
		body.sport();

		body = new VolleyBall_Game("hand", new Playing_VolleyBall());
		body.sport();
	}

}

// 灵魂和肉体是两个不同的维度 不是父子继承关系 但是要组合在一起才能共同完成事情
interface Soul {
	public void sport();
}

// 灵魂要参与运动 但是仅仅灵魂这一个维度没有办法去实现参与运动 比如 踢足球需要脚 打篮球需要手 但是手脚是属于肉体 所以必须把灵魂注入肉体中
class Playing_FootBall implements Soul {

	@Override
	public void sport() {
		System.out.println("playing football");
	}

}

class Playing_BasketBall implements Soul {

	@Override
	public void sport() {
		System.out.println("playing basketball");
	}

}

class Playing_VolleyBall implements Soul {

	@Override
	public void sport() {
		System.out.println("playing volleyball");
	}

}

// 同样 仅仅肉体这一个维度也没有办法完成踢足球和打篮球的运动 因为肉体只有手脚 没有思想 不知道要具体参与什么运动
abstract class Body {
	protected String organ;
	Soul soul;

	public Body(Soul soul) {
		this.soul = soul;
	}

	abstract void sport();

}

class FootBall_Game extends Body {

	public FootBall_Game(String organ, Soul soul) {
		super(soul);
		this.organ = organ;

	}

	@Override
	void sport() {
		soul.sport();
	}

}

class BasketBall_Game extends Body {

	public BasketBall_Game(String organ, Soul soul) {
		super(soul);
		this.organ = organ;
	}

	@Override
	void sport() {
		soul.sport();
	}

}

class VolleyBall_Game extends Body {

	public VolleyBall_Game(String organ, Soul soul) {
		super(soul);
		this.organ = organ;
	}

	@Override
	void sport() {
		soul.sport();
	}

}

输出2:

playing football
playing basketball
playing volleyball

代码3——坐标系例子

package mypackage;

import java.util.Random;

public class DesignPatternDemo {

	public static void main(String[] args) {
		Vertical vertical = new Vertical_Origin(new Horizontal_Origin());
		vertical._draw_Point();

	}

}

abstract class Horizontal {
	public Random random = new Random(47);
	public int x = random.nextInt(100);

	public abstract void _display_x();
}

class Horizontal_Origin extends Horizontal {

	@Override
	public void _display_x() {
		System.out.println("this is Location.X: " + x);
	}

}

abstract class Vertical {
	public Random random = new Random(49);
	public int y = random.nextInt(100);

	public abstract void _display_y();

	public abstract void _draw_Point();

	public Horizontal horizontal;

	public Vertical(Horizontal horizontal) {
		this.horizontal = horizontal;
	}
}

class Vertical_Origin extends Vertical {

	public Vertical_Origin(Horizontal horizontal) {
		super(horizontal);
	}

	@Override
	public void _display_y() {
		System.out.println("this is Location.Y: " + y);

	}

	@Override
	public void _draw_Point() {

		horizontal._display_x();
		_display_y();
	}

}

输出3:

this is Location.X: 58
this is Location.Y: 94

代码4——扩展为立体坐标系:

package mypackage;

import java.util.Random;

public class DesignPatternDemo {

	public static void main(String[] args) {
		Vertical vertical = new Vertical_Origin(new Horizontal_Origin(),new Ordinate_Z_Origin());
		vertical._draw_Point();

	}

}

abstract class Horizontal {
	public Random random = new Random(47);
	public int x = random.nextInt(100);

	public abstract void _display_x();
}

class Horizontal_Origin extends Horizontal {

	@Override
	public void _display_x() {
		System.out.println("this is Location.X: " + x);
	}

}
abstract class Ordinate_Z{
	public Random random=new Random(51);
	public int z=random.nextInt(100);
	public abstract void _display_z();
	
}
class Ordinate_Z_Origin extends Ordinate_Z{

	@Override
	public void _display_z() {
		System.out.println("this is Location.Z: " + z);
	}
	
}
abstract class Vertical {
	public Random random = new Random(49);
	public int y = random.nextInt(100);

	public abstract void _display_y();

	public abstract void _draw_Point();

	public Horizontal horizontal;
    public Ordinate_Z ordinate_Z;
	public Vertical(Horizontal horizontal,Ordinate_Z ordinate_Z) {
		this.horizontal = horizontal;
		this.ordinate_Z=ordinate_Z;
	}
}

class Vertical_Origin extends Vertical {

	public Vertical_Origin(Horizontal horizontal,Ordinate_Z ordinate_Z) {
		super(horizontal, ordinate_Z);
	}

	@Override
	public void _display_y() {
		System.out.println("this is Location.Y: " + y);

	}

	@Override
	public void _draw_Point() {

		horizontal._display_x();
		_display_y();
		ordinate_Z._display_z();
	}

}

输出4:

this is Location.X: 58
this is Location.Y: 94
this is Location.Z: 43

三、小结

很多博客上介绍桥接模式时,两个维度都是一个接口一个抽象类,给人的感觉就好像是两个维度一定要是一个为接口一个为抽象类一样,其实没有必要,设计模式只重其意不重其形,比如上面平面坐标系的例子就是两个抽象类,也可以是两个接口,只要体现面向接口编程的思想就好了。

很多博客上介绍桥接模式时,都是两个维度,给人的感觉就好像桥接模式只能有两个维度似的,也没有必要,设计模式只重其意不重其形,上面的坐标系的例子可以改为立体坐标系 x y z 三个维度,只要能体现桥接模式,各个维度分离的原则就好了。

设计模式只重其意不重其形,在项目开发中也许把因为需求把设计模式扩展或修改了,这并不重要,一切为代码服务,一切为需求服务。

附:桥接模式、代理模式与装饰器模式对比

 桥接模式代理模式装饰器模式
关键类多个维度,各个维度父类和子类代理类装饰类
继承关系各个维度内父类和子类继承关系,便于面向接口编程,各个维度之间类与类没有关系,相互独立实体类和代理类都继承于同一父类,它们与父类是继承关系,便于客户端面向接口编程实体类和装饰类都继承于同一父类,它们与父类是继承关系,便于客户端面向接口编程
组合关系各个维度之间类与类使用组合注入方式联系实体类和代理类之间是组合关系,将实体类引用注入代理类,在代理类中调用实体类方法或属性实体类和装饰类之间是组合关系,将实体类引用注入装饰类,在装饰类中调用实体类方法或属性,还有装饰类自己新增的方法和属性
联系 装饰器模式=代理模式+装饰方法

桥接模式:blog.csdn.net/qq_36963950…

代理模式:blog.csdn.net/qq_36963950…

装饰器模式:blog.csdn.net/qq_36963950…

 

上一篇:设计模式(六)——适配器模式

下一篇:设计模式(八)——代理模式