使用Java桥接模式打破继承束缚优雅实现多维度变化
作者:陈书予 发布时间:2023-08-23 09:00:34
一、导言
1.1 介绍桥接模式及其应用背景
桥接模式(Bridge Pattern)是一种结构型设计模式,它将抽象部分与实现部分分离,使它们可以独立变化。该模式通过创建抽象类和实现类之间的桥梁,将它们联系起来。这样一来,抽象类和实现类就可以分别修改而不会影响到彼此。桥接模式的主要思想是面向接口编程和实现分离。
在软件开发中,经常遇到需要改变系统中某些部分的实现,而不希望对客户端产生影响。例如,在开发一个绘图程序时,需要对图形对象进行绘制操作,但是绘制操作的方式可能是使用不同的绘制工具,例如画笔、颜料等等。如果在图形对象中嵌入绘制操作,那么在更改绘制工具时,需要修改图形对象的代码,这样就会影响到客户端程序。为了避免这种情况,可以使用桥接模式来将图形对象和绘制工具进行分离,使得它们可以独立变化。
1.2 提出文章的主要目的和内容概述
本文的主要目的是介绍桥接模式的设计原则和工作原理,讲解桥接模式的应用场景和使用方法,并通过代码示例和实际案例展示桥接模式的实现过程和应用方法。同时,本文还将分析桥接模式与其他设计模式的区别和优缺点,并探讨桥接模式在未来的发展和应用前景。
二、设计原则和模式分析
1.1 讲解面向接口编程和实现分离的设计原则
在软件开发中,面向接口编程和实现分离是一种非常重要的设计原则。面向接口编程是指,将系统中的各个部分都看作是一个独立的组件,通过定义接口来规范组件之间的交互方式,从而实现组件之间的松耦合。实现分离是指,将系统中的各个部分的实现和接口进行分离,使得它们可以独立变化。这样一来,系统的各个部分就可以分别进行开发和测试,而不会互相影响。桥接模式就是一种实现面向接口编程和实现分离的设计模式。它通过将抽象类和实现类分离,将抽象部分和实现部分进行解耦,从而实现系统的灵活性和可扩展性。在桥接模式中,抽象类和实现类之间通过桥梁进行联系,这样一来,抽象类和实现类之间就可以独立变化,不会互相影响。同时,桥接模式还可以避免出现类 * 的情况,即由于类的数量过多而导致代码难以维护的问题。
2.2 探讨桥接模式的工作原理和使用场景
在桥接模式中,抽象化角色包含了一个指向实现化角色的引用,它定义了一个与实现化角色进行交互的接口。实现化角色则提供了一个接口来实现具体的操作。具体抽象化角色和具体实现化角色则是抽象化角色和实现化角色的具体实现。
桥接模式适用于以下场景:
系统中某个类存在多个实现,但是这些实现不应该对客户端产生影响。
需要在系统中进行抽象化和实现化之间的解耦。
需要在开发过程中灵活地切换和组合不同的抽象类和实现类。
2.3 分析桥接模式与其他设计模式的区别和优缺点
桥接模式与其他设计模式的区别在于,它主要关注于抽象化角色和实现化角色之间的关系,而不是像适配器模式那样将一个接口转换为另一个接口。桥接模式的优点在于,它可以将系统中的抽象部分和实现部分进行解耦,从而实现系统的灵活性和可扩展性。缺点在于,它会增加系统的复杂度,因为需要额外定义抽象化角色和实现化角色之间的桥梁。
三、桥接模式的实现
3.1 介绍桥接模式的四个角色
桥接模式中包含了四个角色:抽象化角色、实现化角色、具体抽象化角色、具体实现化角色。其中,抽象化角色和实现化角色是抽象类,具体抽象化角色和具体实现化角色是具体类。
3.2 利用代码示例展示具体的实现过程
四、桥接模式的应用案例
4.1 通过一个简洁的程序案例,展示桥接模式的基本实现
假设我们在写一个图形类,支持多种颜色来填充这个图形,我们可以使用桥接模式,实现图形类和颜色类的分离,而不是让它们紧密耦合。
interface Color {
void fill();
}
class RedColor implements Color {
public void fill() {
System.out.println("填充红色");
}
}
class BlueColor implements Color {
public void fill() {
System.out.println("填充蓝色");
}
}
abstract class Shape {
protected Color color;
public Shape(Color color) {
this.color = color;
}
abstract void draw();
}
class Rectangle extends Shape {
public Rectangle(Color color) {
super(color);
}
void draw() {
System.out.print("矩形 ");
color.fill();
}
}
class Circle extends Shape {
public Circle(Color color) {
super(color);
}
void draw() {
System.out.print("圆形 ");
color.fill();
}
}
public class BridgeDemo {
public static void main(String[] args) {
Color red = new RedColor();
Color blue = new BlueColor();
Shape rectangle = new Rectangle(red);
rectangle.draw();
Shape circle = new Circle(blue);
circle.draw();
}
}
输出结果:
矩形 填充红色
圆形 填充蓝色
这里,Shape 类作为抽象类,它包含一个 Color 实例,表示这个图形的填充颜色,还有抽象方法 draw(),表示绘制这个图形。
Rectangle 和 Circle 类是 Shape 的子类,分别表示矩形和圆形。
RedColor 和 BlueColor 类分别实现 Color 接口,表示红色和蓝色。
最后在 main() 函数中,我们创建好了红色和蓝色的实例,将它们传入矩形和圆形的构造函数中,表示这个矩形和圆形需要用红色和蓝色来填充。
4.2 通过一个更加复杂的实例,说明桥接模式如何在真实的开发中应用
假设我们正在开发一个电商网站,其中有各种类型的产品,如服装、家具、食品等。此外,我们还希望网站能够支持多种支付方式,例如信用卡、PayPal、Apple Pay等。在这种情况下,我们可以使用桥接模式来实现产品和支付方式之间的解耦。
首先,我们需要定义两个抽象类:Product和Payment。Product类表示所有产品的抽象,Payment类表示所有支付方式的抽象。
public abstract class Product {
protected Payment payment;
public Product(Payment payment) {
this.payment = payment;
}
public abstract void purchase();
}
public abstract class Payment {
public abstract void pay(double amount);
}
接下来,我们可以定义具体的产品和支付方式,例如Clothing、Furniture、Food类和CreditCard、PayPal、ApplePay类。
public class Clothing extends Product {
public Clothing(Payment payment) {
super(payment);
}
@Override
public void purchase() {
payment.pay(50.0);
System.out.println("Purchased clothing for $50.0");
}
}
public class CreditCard extends Payment {
@Override
public void pay(double amount) {
System.out.println("Paid $" + amount + " with credit card.");
}
}
考虑到我们可以有多种支付方式,我们可以在Payment类中定义一个接口,让具体的支付方式实现该接口。
public abstract class Payment {
protected PaymentMethod paymentMethod;
public Payment(PaymentMethod paymentMethod) {
this.paymentMethod = paymentMethod;
}
public abstract void pay(double amount);
public void setPaymentMethod(PaymentMethod paymentMethod) {
this.paymentMethod = paymentMethod;
}
}
public interface PaymentMethod {
public void pay(double amount);
}
public class CreditCard extends Payment implements PaymentMethod {
public CreditCard() {
super(new CreditCardPaymentMethod());
}
@Override
public void pay(double amount) {
paymentMethod.pay(amount);
}
}
public class CreditCardPaymentMethod implements PaymentMethod {
@Override
public void pay(double amount) {
System.out.println("Paid $" + amount + " with credit card.");
}
}
使用桥接模式,我们可以在运行时动态地将Payment的具体实现与PaymentMethod的具体实现进行组合,从而得到多种不同的组合,实现产品和支付方式之间的解耦。例如,我们可以使用如下代码来购买一件服装并使用信用卡进行支付:
Product clothing = new Clothing(new CreditCard());
clothing.purchase();
同样,我们可以像下面这样使用桥接模式来购买其他的产品并使用其他的支付方式:
Product furniture = new Furniture(new PayPal());
furniture.purchase();
Product food = new Food(new ApplePay());
food.purchase();
通过这种方式,我们可以轻松地扩展产品和支付方式,从而更好地满足客户的需求。
五、总结和思考
5.1 总结桥接模式的优点和不足,并探讨如何在实际项目中更好地运用
优点:
容易扩展。由于抽象与实现分离,因此可以更容易地添加新的实现类或抽象类而不需要修改现有的代码。
易于维护。桥接模式使用聚合关系,而不是继承关系进行实现。这样使代码更容易维护和测试。
提高代码的复用性。可以通过修改抽象接口或实现类来使多个模块重用相同的代码。
减少了代码的复杂性。通过将实现代码和抽象代码分开,桥接模式减少了代码的复杂性。
缺点:
增加类的数量。桥接模式需要定义抽象类和实现类之间的接口,这将增加类的数量。
可能会导致性能下降。由于需要进行额外的接口调用,桥接模式可能会导致性能下降。
如何在实际项目中更好地运用:
在设计类时尽量遵循桥接模式的原则,尤其是对于那些可能变化的部分,需要将它们抽象出来。
使用桥接模式时需要确保抽象类和实现类之间的接口定义足够清晰,以便于后续的扩展和维护。
在具体实现中,我们需要采用工厂模式以及依赖注入等方式来创建和注入抽象和具体实现类。
5.2 探索桥接模式在未来的发展和应用前景
扩展性:桥接模式可以通过添加新的抽象接口和具体实现来扩展系统,而不会影响原有代码的功能。这使得系统更具灵活性和可扩展性。
模块化:桥接模式可以将系统分解为多个组件,每个组件负责不同的任务。这使得系统更加模块化、可维护、易于管理。
透明性:桥接模式可以隐藏具体实现的细节,使得系统更加简化、易于理解。
统一性:桥接模式可以将不同实现统一起来,增强系统的一致性和协作性。
应用范围扩展:桥接模式已经被广泛应用于计算机、通信、制造、航空、医疗等领域,未来将继续在这些领域应用,并开始向物联网、大数据、人工智能等领域扩展。
总体来说,桥接模式的未来发展和应用前景是非常广阔的,它将继续发挥其优雅、简便、易扩展的特点,成为许多系统设计的首选模式。
来源:https://juejin.cn/post/7230996966343671867


猜你喜欢
- 本文实例为大家分享了unity3d实现七天签到功能的具体代码,供大家参考,具体内容如下在很多游戏中都有签到功能,(这里记录的是7天连续签到功
- 前言前面的例子都是多个线程在做相同的操作,比如4个线程都对共享数据做tickets–操作。大多情况下,程序中需要不同的线程做不同的事,比如一
- 查看JDK1.8 ArrayList的源代码1、默认初始容量为10 /** * Default i
- 本文实例为大家分享了Android实现秒表功能的具体代码,供大家参考,具体内容如下设计完成一个秒表,具备启停功能,正确使用工作线程完成界面刷
- 前言在java里,当我们需要拷贝一个对象时,有两种类型的拷贝:浅拷贝与深拷贝。浅拷贝只是拷贝了源对象的地址,所以源对象的值发生变化时,拷贝对
- 实现InsertOrUpdate功能需求最近在项目开发中遇到这样一个需求:每天需要对相同的数据(也有可能是不同的)进行两次入库操作,数据不存
- 很多朋友在下载文件的时候,经常会发现网站提供了MD5校验码,其实这个MD5码的作用就是当你下载文件好了之后,拿你下载好的文件的MD5校验码,
- 接着上一篇再为大家介绍java应用和输入输出常用方法,供大家参考,具体内容如下一、应用1、使用StringBuilder或StringBuf
- 通过路径从磁盘直接读取图片这段时间在做Springboot和Vue的例子,读取图片给出路径直接可以读,太方便了,一直么有搞懂为什么。后面看到
- 本文实例讲述了Android编程使用AlarmManager设置闹钟的方法。分享给大家供大家参考,具体如下:package com.Aina
- 关于logback日志的详解见这位仁兄的博客:Spring Boot-日志配置(超详细)我在这就开门见山直接介绍我们项目日志的配置使用吧!~
- MyCat一个彻底开源的,面向企业应用开发的大数据库集群。基于阿里开源的Cobar产品而研发。能满足数据库数据大量存储;提高了查询性能。文章
- 使用Collections.sort对中文进行排序使用collections.sort(List list, Comparator <
- 我们在编写网络程序的时候,经常会进行如下操作:申请一个缓冲区从数据源中读入数据至缓冲区解析缓冲区的数据重复第2步表面上看来这是一个很常规而简
- 在 javax.validation.constraints包中定义了非常多的校验注解,引入依赖:<dependency> &n
- 1、实现原理不同过滤器和 * 底层实现方式大不相同,过滤器 是基于函数回调的, * 则是基于Java的反射机制( * )实现的。1、拦
- java * 的方法总结AOP的拦截功能是由java中的 * 来实现的。说白了,就是在目标类的基础上增加切面逻辑,生成增强的目标类(该
- 一、Lombok从上一篇博客可看出,DAO接口类的编写变得简单,反过来看模型,编写还需要(私有属性、setter...getter...方法
- 本文实例讲述了Java Base64算法实际应用之邮件发送。分享给大家供大家参考,具体如下:一 利用telnet和Base64来实现收发邮件
- 概念优先级队列是一种先进先出(FIFO)的数据结构,与队列不同的是,操作的数据带有优先级,通俗的讲就是可以比较大小,在出队列的时候往往需要优