提问者:小点点

桥接模式是否将抽象与实现分离?


我从不同的文章中学习了桥接模式,并根据我的理解实现了这一点。让我困惑的一件事是桥接模式说

BridgePattern将抽象与其实现解耦,以便两者可以独立变化

这句话的意思是什么?实现是否存在于单独的jar?

独立陈述的含义是什么?

考虑提供的日志开发文章,详细说明答案。

任何帮助都非常感谢。


共3个答案

匿名用户

BridgePattern将抽象与其实现解耦。

抽象和实现可以独立变化,因为具体类不直接实现抽象(接口)

实现从不引用抽象。抽象包含实现接口作为成员(通过组合)。

回到您关于[logaldev][4]文章中示例代码的问题:

形状是抽象的

三角形被重新定义抽象

颜色是实施者

RedColor是混凝土实施者

一个具体的形状对象:三角形扩展形状,但不实现颜色接口。

public class Triangle extends Shape{
}

RedColor和GreenColor实际上实现了Color接口。

混凝土形状对象(三角形)独立于实现抽象(即颜色接口)。

Shape tri = new Triangle(new RedColor());

这里三角形包含一个具体的Color对象(Comence)。如果Color抽象(接口)有变化,RedColor和GreenColor负责实现Color接口的抽象。

像三角形这样的形状不受颜色接口契约变化的影响。因此颜色接口可以独立变化。这是可能的,因为Shape持有使用组合而不是实现的契约。

更好地理解模式的示例代码:

示例代码:

/* Implementor interface*/
interface Gear{
    void handleGear();
}

class VehicleAttributes{
    String name;
    String engineID;
    String chasisNumber;
    int seats;
    int engineCapacity;
    double height;
    double length;
}

/* 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;
    /* Mutable state of Vehicle */
    VehicleAttributes attributes;
    public Vehicle(Gear gear){
        this.gear = gear;
    }
    abstract void addGear();
    public void setVehicleAttributes(VehicleAttributes attributes){
        this.attributes = attributes;
    }
    
}
/* 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();
        /* Create specific properties of Car in attributes */
        //vehicle.setVehicleAttributes(attributes);
        
        gear = new ManualGear();
        vehicle = new Truck(gear);
        vehicle.addGear();
        /* Create specific properties of Truck in attributes */
        //vehicle.setVehicleAttributes(attributes);
        
        gear = new AutoGear();
        vehicle = new Truck(gear);
        vehicle.addGear();
        /* Create specific properties of Truck in attributes */
        //vehicle.setVehicleAttributes(attributes);
    }
}

输出:

Car handles Manual gear
Car handles Auto gear
Truck handles Manual gear
Truck handles Auto gear

解释:

  1. 车辆是一个抽象。
  2. CarTruck车辆的两个具体实现。
  3. 车辆定义了一个抽象方法:addGear()
  4. Gear是实现者接口
  5. ManualGearAutoGearGear
  6. 的两个实现
  7. 车辆包含实现者接口而不是实现接口。实现者接口的Compositon是这种模式的关键:它允许抽象和实现独立变化。
  8. CarTruck定义抽象的实现(重新定义的抽象):addGear():它包含Gear-手动Auto

桥接模式的用例:

  1. 抽象和实现可以相互独立地更改,并且它们在编译时不受约束
  2. 映射正交层次结构-一个用于抽象,一个用于实现。

匿名用户

这个语句的简单意思是,你可以在运行时切换抽象指向的实现器,一切都应该工作(就像在策略模式中一样;但是在策略模式中,只有策略是抽象的)。它也可以被理解为分离两个类,这样它们就不必相互了解,而不仅仅是它们的接口。

匿名用户

对我来说,Bridge并不是GOF圣经中最重要的DP,因为它主要是Strategy的衍生产品。作为其他一些没有老化的模式(工厂方法?),它意味着抽象类持有行为的继承比其他模式更多,因此不太普遍适用。

主要是战略在做大事,但战略的一个主要问题是战略通常需要了解其背景。

在某些语言中,这会导致策略被声明为上下文的朋友,或者策略被定义为Java中的内部类。

这意味着上下文通常最终会知道各种具体策略的存在。您可以通过使用setStrategy()函数来避免这种情况,但是由于效率原因(您希望直接操作上下文的数据结构),从具体策略到上下文的反向依赖通常会保留下来。

Bridge解决了这个问题,因为Strategy的上下文现在是抽象的,但仍然是一个先验的类,因为它至少有Strategy的代码。它通常应该定义一个足以让具体策略使用的访问API,可能有洞,即抽象方法。你在AbstractStragey上的操作签名中出现了AbstractContext,你就很好了。

因此,在我看来,Bridge通过使Context足够具体以使策略工作来完成策略,但仍然足够抽象,以至于它可以正交地细化具体策略(在实现具体策略实际使用的上下文的抽象API时具有反馈效果)。

一种更简单的看待桥的方法是说AbstractStrategy操作应该始终将抽象作为参数,而不是真正了解它们的上下文。

要更准确地回答OP问题:

这句话的意思是什么?实现是否存在于单独的jar?

是的,实际上,通常你可以在一个包“base”(tey可以是接口)中定义抽象和实现器。具体的实现器可以各自驻留在一个包“implXX”中。具体的上下文可以驻留在单独的包“contXX”中。依赖图中没有循环,每个人都依赖于base,新的“contXX”和“implXX”可以独立定义(它们之间根本没有依赖关系),因此OP中的粗体语句。

独立陈述的含义是什么?

想象一下eclipse中的编辑器插件;它必须处理按钮和点击上的操作(就像策略一样),但策略需要做的实际操作是作用于编辑器状态本身(例如“突出显示文本”)。您以抽象的方式定义编辑器拥有的内容,包括它具有用于clics和keypress的Handler以及突出显示和导航功能,即使这些功能也可以被具体的编辑器覆盖(flash而不是突出显示)。这是一座桥梁,您可以独立定义新的编辑器和新的处理程序。

通过一些依赖注入(例如Google guice)或一些手动工厂代码或组件方向来从外部干净地设置Strategy,您可以获得应用程序各个部分的非常低的耦合。

考虑提供的日志开发文章,详细说明答案。

老实说,我认为这不是DP的最佳应用,因为颜色实现似乎不太关心它们的上下文。你应该在这里使用装饰器,因为颜色是形状的独立关注点。

看看这些幻灯片,了解装饰器的解决方案(部分是法语,抱歉)。https://www-licence.ufr-info-p6.jussieu.fr/lmd/licence/2015/ue/3I002-2016fev/cours/cours-9.pdf(幻灯片16-18)基于这里介绍的示例:https://www-licence.ufr-info-p6.jussieu.fr/lmd/licence/2015/ue/3I002-2016fev/cours/cours-4.pdf幻灯片10到15。

在这个例子中,如果“updateInertie”是Forme的成员,我们需要Bridge,这听起来并不荒谬。同样,Bridge更多地是作为其他模式的组合出现的。