当你使用桥模式?它是如何不同于适配模式?
-
11-07-2019 - |
题
有没有人用过的 桥模式 在现实世界的应用程序?如果是这样,你怎么用它呢?是我,或者是它仅适配器模式与一个小小的依赖注射抛入混?它是否真的值得其自己的模式?
其他提示
桥图案是旧的建议的应用中,“喜欢在组合物继承”。 它成为方便的时候你必须是正交彼此的方式继承不同的时间。说你必须实现彩色形状的层次结构。你不会用矩形和圆形形状的子类,然后用RedRectangle,BlueRectangle和GreenRectangle与同为圆矩形的子类,你会吗?你更愿意说,每个形状的的的颜色和落实的色彩层次,那就是桥接模式。好了,我也不会实施“的色彩层次”,但你的想法......
当:
A
/ \
Aa Ab
/ \ / \
Aa1 Aa2 Ab1 Ab2
重构为:
A N
/ \ / \
Aa(N) Ab(N) 1 2
适配器和桥被肯定有关,区别是微妙的。这可能是因为有些人谁认为他们使用这些模式的一个实际使用的其他模式。
我见过的解释是,适配器,当你试图统一是有些不适应类的接口已经存在的使用。适配器用作一种翻译来实现,它们可以被认为遗留
鉴于桥模式被用于代码,更容易被新生产能力。你设计的桥梁,为需要改变的实现提供了一个抽象的接口,但也定义的实现类的接口。
设备驱动程序是桥一个经常被引用的例子,但我会说这是一个桥梁,如果你定义了设备制造商的接口规范,但如果你利用现有的设备驱动程序,使包装它是一个适配器-class提供一个统一的接口。
所以代码明智的,这两个图案非常相似。商业的角度来看,他们是不同的。
在我的经验,桥是一个经常重复的模式,因为它的解决方案,只要有域中两个正交尺寸。例如。形状和绘制方法,行为和平台,文件格式和串行器等等。
和一个建议:一直认为设计模式从概念角度看的,而不是从实现的角度来看的。从视右点,桥不能与适配器混淆,因为它们解决不同的问题,而组合物是优异的继承不本身的缘故,而是因为其允许单独地处理正交关注。
的意图 桥 和 适配器 是不同的,我们分别需要两种模式。
桥接模式:
- 这是一种结构模式
- 抽象和实现在编译时不受约束
- 抽象和实现 - 两者都可以变化而不影响客户端
- 使用组合而不是继承。
在以下情况下使用桥接模式:
- 您想要实现的运行时绑定,
- 由于耦合的接口和大量的实现,您会产生大量的类,
- 您想在多个对象之间共享一个实现,
- 您需要映射正交的类层次结构。
@John Sonmez 的回答清楚地表明了桥接模式在减少类层次结构方面的有效性。
您可以参考下面的文档链接,通过代码示例更好地了解桥接模式
适配器模式:
- 它 允许两个不相关的接口一起工作 通过不同的对象,可能扮演相同的角色。
- 修改了原来的界面。
主要区别:
- 适配器 设计完成后让事情发挥作用; 桥 让他们先于工作。
- 桥 是预先设计的,让 抽象和实现独立变化. 适配器 经过改造以使不相关的类一起工作。
- 意图: 适配器 允许两个不相关的接口一起工作。 桥 允许抽象和实现独立变化。
与 UML 图和工作代码相关的 SE 问题:
有用的文章:
源头制造桥梁 图案文章
源制作适配器 图案文章
日志开发桥 图案文章
编辑:
桥接模式真实世界示例(根据 meta.stackoverflow.com 建议,在本文中合并了文档站点示例,因为文档即将结束)
桥接模式将抽象与实现分离,以便两者可以独立变化。它是通过组合而不是继承来实现的。
来自维基百科的桥接模式 UML:
此模式中有四个组件。
Abstraction
: :它定义了一个接口
RefinedAbstraction
: :它实现了抽象:
Implementor
: :它定义了一个接口来实现
ConcreteImplementor
: :它实现了 Implementor 接口。
The crux of Bridge pattern :
使用组合(并且无继承)的两个正交类层次结构。抽象层次结构和实现层次结构可以独立变化。实现从来不涉及抽象。抽象包含实现接口作为成员(通过组合)。这种组合又减少了一层继承层次结构。
真实的用例:
使不同的车辆具有手动和自动两个版本的齿轮系统。
示例代码:
/* Implementor interface*/
interface Gear{
void handleGear();
}
/* Concrete Implementor - 1 */
class ManualGear implements Gear{
public void handleGear(){
System.out.println("Manual gear");
}
}
/* Concrete Implementor - 2 */
class AutoGear implements Gear{
public void handleGear(){
System.out.println("Auto gear");
}
}
/* Abstraction (abstract class) */
abstract class Vehicle {
Gear gear;
public Vehicle(Gear gear){
this.gear = gear;
}
abstract void addGear();
}
/* RefinedAbstraction - 1*/
class Car extends Vehicle{
public Car(Gear gear){
super(gear);
// initialize various other Car components to make the car
}
public void addGear(){
System.out.print("Car handles ");
gear.handleGear();
}
}
/* RefinedAbstraction - 2 */
class Truck extends Vehicle{
public Truck(Gear gear){
super(gear);
// initialize various other Truck components to make the car
}
public void addGear(){
System.out.print("Truck handles " );
gear.handleGear();
}
}
/* Client program */
public class BridgeDemo {
public static void main(String args[]){
Gear gear = new ManualGear();
Vehicle vehicle = new Car(gear);
vehicle.addGear();
gear = new AutoGear();
vehicle = new Car(gear);
vehicle.addGear();
gear = new ManualGear();
vehicle = new Truck(gear);
vehicle.addGear();
gear = new AutoGear();
vehicle = new Truck(gear);
vehicle.addGear();
}
}
输出:
Car handles Manual gear
Car handles Auto gear
Truck handles Manual gear
Truck handles Auto gear
解释:
Vehicle
是一个抽象。Car
和Truck
是两个具体实现Vehicle
.Vehicle
定义一个抽象方法:addGear()
.Gear
是实现者接口ManualGear
和AutoGear
是两个实现Gear
Vehicle
包含implementor
接口而不是实现接口。Compositon
实现者接口的实现是该模式的关键: 它允许抽象和实现独立变化。Car
和Truck
为抽象定义实现(重新定义抽象):addGear()
:它包含Gear
- 任何一个Manual
或者Auto
桥接模式的用例:
- 抽象 和 执行 可以相互独立地改变并且它们在编译时不绑定
- 映射正交层次结构 - 一个用于 抽象 和一个用于 执行.
我已经使用在工作桥图案。 I程序在C ++中,在那里它通常被称为PIMPL成语(指针实现)。它看起来像这样:
class A
{
public:
void foo()
{
pImpl->foo();
}
private:
Aimpl *pImpl;
};
class Aimpl
{
public:
void foo();
void bar();
};
在这个例子中class A
包含接口,和class Aimpl
包含实现。
对于这种模式的一个用途是只揭露一些实现类的公共成员的,而不是其他。在该示例中仅Aimpl::foo()
可以通过A
的公共接口调用,但不能Aimpl::bar()
另一个优点是,可以在不需要由Aimpl
的用户被包括在单独的头文件中定义A
。你所要做的就是使用Aimpl
的正向声明A
定义之前,和移动的所有成员函数引用pImpl
到.cpp文件中定义。这使你保持Aimpl
头专用,并减少编译时间的能力。
要放形状例在代码:
#include<iostream>
#include<string>
#include<cstdlib>
using namespace std;
class IColor
{
public:
virtual string Color() = 0;
};
class RedColor: public IColor
{
public:
string Color()
{
return "of Red Color";
}
};
class BlueColor: public IColor
{
public:
string Color()
{
return "of Blue Color";
}
};
class IShape
{
public:
virtual string Draw() = 0;
};
class Circle: public IShape
{
IColor* impl;
public:
Circle(IColor *obj):impl(obj){}
string Draw()
{
return "Drawn a Circle "+ impl->Color();
}
};
class Square: public IShape
{
IColor* impl;
public:
Square(IColor *obj):impl(obj){}
string Draw()
{
return "Drawn a Square "+ impl->Color();;
}
};
int main()
{
IColor* red = new RedColor();
IColor* blue = new BlueColor();
IShape* sq = new Square(red);
IShape* cr = new Circle(blue);
cout<<"\n"<<sq->Draw();
cout<<"\n"<<cr->Draw();
delete red;
delete blue;
return 1;
}
的输出是:
Drawn a Square of Red Color
Drawn a Circle of Blue Color
请注意与新的颜色和形状可以被添加到系统中而不会导致子类的爆炸由于置换的容易性。
对于我来说,我认为它作为一种机制,在那里你可以交换接口。在现实世界中,你可能有一个类,可以使用一个以上的接口,大桥让你交换。
Bridge design pattern we can easily understand helping of service and dao layer.
Dao layer -> create common interface for dao layer ->
public interface Dao<T>{
void save(T t);
}
public class AccountDao<Account> implement Dao<Account>{
public void save(Account){
}
}
public LoginDao<Login> implement Dao<Login>{
public void save(Login){
}
}
Service Layer ->
1) interface
public interface BasicService<T>{
void save(T t);
}
concrete implementation of service -
Account service -
public class AccountService<Account> implement BasicService<Account>{
private Dao<Account> accountDao;
public AccountService(AccountDao dao){
this.accountDao=dao;
}
public void save(Account){
accountDao.save(Account);
}
}
login service-
public class LoginService<Login> implement BasicService<Login>{
private Dao<Login> loginDao;
public AccountService(LoginDao dao){
this.loginDao=dao;
}
public void save(Login){
loginDao.save(login);
}
}
public class BridgePattenDemo{
public static void main(String[] str){
BasicService<Account> aService=new AccountService(new AccountDao<Account>());
Account ac=new Account();
aService.save(ac);
}
}
}