java 设计模式之桥梁模式

1,524 阅读5分钟

1.引言

SEC安全系统是一家生产和组装汽车产品的安全和电子公司。它提供任何你想要的汽车电子或安全系统,从安全气囊到GPS跟踪系统,倒车停车系统等。大型汽车公司在他们的汽车中使用它的产品。公司使用一种定义良好的面向对象的方法,使用他们开发和维护的软件来跟踪他们的产品。他们得到汽车,为它生产系统,然后把它组装到汽车上。

最近,他们接到了Bigwheel(一家汽车公司)的新订单,为他们的新XZ车型生产中控锁和齿轮锁系统。为了维护这一点,他们正在创建一个新的软件系统。他们首先创建了一个新的抽象类 CarProductSecurity,在这个类中保留了一些特定于汽车的方法和一些他们认为对所有安全产品都通用的特性。然后他们扩展了类并创建了两个不同的子类,分别命名为BigWheelXZCentralLockingBigWheelXZGearLocking。类图如下所示:

过了一会儿,另一家汽车公司Motoren要求他们为他们的LM车型生产一种新的中控锁和齿轮锁系统。由于相同的安全系统不能用于不同车型的两种车型,因此SEC安全系统已经为它们生产了新的系统,并已创建了新的等级MotorEnlmCentrallockingMotorEnlmGearLocking,这也扩展了CarProductSecurity等级。 现在,新的类图如下所示:

到目前为止还不错,但如果另一家汽车公司需要另一套新的中控锁和齿轮锁系统,会发生什么呢?一个需要为它创建另外两个新类。这种设计将为每个系统创建一个类,或者更糟的是,如果为这两个汽车公司中的每一个生产反向停车系统,则将为每个公司再创建两个新类。

子类太多的设计不灵活,难以维护。继承还将实现永久绑定到抽象,这使得独立地修改、扩展和重用抽象和实现变得困难。

请注意,为了使软件系统易于扩展和重用,汽车和产品应独立变化。

桥梁设计模式可以解决这个问题,但在此之前,让我们先了解一些关于桥梁模式的细节。

2.什么是桥梁模式

桥梁模式的目的是将抽象从其实现中分离出来,这样两个抽象就可以独立变化。它将抽象和实现放在两个不同的类层次结构中,以便两者都可以独立扩展。

桥梁的组成部分包括抽象、精抽象、实现者和具体实现者。 抽象定义了抽象的接口,还维护了对类型为实现者的对象的引用,抽象和实现者之间的链接称为桥。

3.实例

在上面讨论的问题中,我们不需要为每个汽车模型的每个产品创建子类,而是可以将设计分为两个不同的层次结构。一个接口用于将用作实现者的产品,另一个接口将是汽车类型的抽象。实现者将由具体的实现者实现,并为其提供实现。另一方面,抽象将通过更精细的抽象来扩展。

package com.javacodegeeks.patterns.bridgepattern;
public interface Product {
    public String productName();
    public void produce();
}

实现者产品有一个方法product(),具体实现者将使用该方法为其提供具体的功能。该方法将生成产品的基本模型,经过特定于该车型的一些修改后,可以与任何车型一起使用。

package com.javacodegeeks.patterns.bridgepattern;
public class CentralLocking implements Product{
    private final String productName;
    public CentralLocking(String productName){
        this.productName = productName;
    }
    @Override
    public String productName() {
        return productName;
    }
    @Override
    public void produce() {
        System.out.println("Producing Central Locking System");
    }
 
}
 
package com.javacodegeeks.patterns.bridgepattern;
public class GearLocking implements Product{
    private final String productName;
    public GearLocking(String productName){
        this.productName = productName;
    }
    @Override
    public String productName() {
        return productName;
    }
    @Override
    public void produce() {
        System.out.println("Producing Gear Locking System");
    }
}

两个不同的具体实现者为产品实现者提供实现。 现在抽象Car类,它保存了产品类型的引用,并提供了两个抽象方法produceproduct()assembly()

package com.javacodegeeks.patterns.bridgepattern;
public abstract class Car {
    private final Product product;
    private final String carType;
    public Car(Product product,String carType){
        this.product = product;
        this.carType = carType;
    }
    public abstract void assemble();
    public abstract void produceProduct();
    public void printDetails(){
        System.out.println("Car: "+carType+", Product:"+product.productName());
    }
}

Car的子类将为assembly()produceProduct()方法提供具体的具体实现。

package com.javacodegeeks.patterns.bridgepattern;
public class BigWheel extends Car{
    private final Product product;
    private final String carType;
    public BigWheel(Product product, String carType) {
        super(product, carType);
        this.product = product;
        this.carType = carType;
    }
 
    @Override
    public void assemble() {
        System.out.println("Assembling "+product.productName()+" for "+carType);
    }
 
    @Override
    public void produceProduct() {
        product.produce();
        System.out.println("Modifing product "+product.productName()+" according to "+carType);
    }
 
}
 
package com.javacodegeeks.patterns.bridgepattern;
public class Motoren extends Car{
    private final Product product;
    private final String carType;
    public Motoren(Product product, String carType) {
        super(product, carType);
        this.product = product;
        this.carType = carType;
    }
 
    @Override
    public void assemble() {
        System.out.println("Assembling "+product.productName()+" for "+carType);
    }
 
    @Override
    public void produceProduct() {
        product.produce();
        System.out.println("Modifing product "+product.productName()+" according to "+carType);
    }
 
}

现在,让我们测试这个例子。

package com.javacodegeeks.patterns.bridgepattern;
 
public class TestBridgePattern {
 
    public static void main(String[] args) {
        Product product = new CentralLocking("Central Locking System");
        Product product2 = new GearLocking("Gear Locking System");
        Car car = new BigWheel(product , "BigWheel xz model");
        car.produceProduct();
        car.assemble();
        car.printDetails();
         
        System.out.println();
         
        car = new BigWheel(product2 , "BigWheel xz model");
        car.produceProduct();
        car.assemble();
        car.printDetails();
         
        System.out.println("-----------------------------------------------------");
         
        car = new Motoren(product, "Motoren lm model");
        car.produceProduct();
        car.assemble();
        car.printDetails();
         
        System.out.println();
         
        car = new Motoren(product2, "Motoren lm model");
        car.produceProduct();
        car.assemble();
        car.printDetails();
         
    }
 
}

上述示例将生成以下输出:

Producing Central Locking System
Modifing product Central Locking System according to BigWheel xz model
Assembling Central Locking System for BigWheel xz model
Car: BigWheel xz model, Product:Central Locking System
 
Producing Gear Locking System
Modifing product Gear Locking System according to BigWheel xz model
Assembling Gear Locking System for BigWheel xz model
Car: BigWheel xz model, Product:Gear Locking System
-----------------------------------------------------
Producing Central Locking System
Modifing product Central Locking System according to Motoren lm model
Assembling Central Locking System for Motoren lm model
Car: Motoren lm model, Product:Central Locking System
 
Producing Gear Locking System
Modifing product Gear Locking System according to Motoren lm model
Assembling Gear Locking System for Motoren lm model
Car: Motoren lm model, Product:Gear Locking System

4.什么时候使用桥梁模式

在以下情况下,应使用桥接模式:

  • 您希望避免抽象及其实现之间的永久绑定。
  • 抽象及其实现都应该通过子类进行扩展。在本例中,桥梁模式允许您组合不同的抽象和实现,并独立地扩展它们。
  • 抽象实现中的更改不应对客户机产生影响;也就是说,不必重新编译他们的代码。