Bridge Design Pattern
Abstraction-ı implementation-dan ayırmağa imkan verir. Bu pattern, iki ayrı hierarchy yaradır - biri abstraction üçün, digəri isə implementation üçün. Bu iki hierarchy bir-birindən asılı olmadan inkişaf edə bilər.
Bridge pattern, "Composition over Inheritance" prinsipini tətbiq edir. Bu pattern, inheritance hierarchies-ni çoxaltmaq əvəzinə, abstraction və implementation arasında körpü (bridge) yaradır. Bu, kod-un daha flexible və maintainable olmasını təmin edir.
Bridge Pattern-nin Əsas Xüsusiyyətləri
- Decoupling Interface and Implementation: Interface və implementation-ı bir-birindən ayırır
- Improved Extensibility: Abstraction və implementation-ı ayrı-ayrılıqda genişləndirməyə imkan verir
- Hiding Implementation Details: Client-dən implementation detallarını gizlədir
- Composition over Inheritance: Inheritance əvəzinə composition istifadə edir
Bridge Pattern-nin Strukturu
- Abstraction: Yüksək səviyyəli abstraction təyin edən interface və ya abstract class
- Refined Abstraction: Abstraction-ı genişləndirən və əlavə funksionallıq təqdim edən class
- Implementor: Implementation interface-ni təyin edən interface və ya abstract class
- Concrete Implementor: Implementor interface-ni implement edən konkret class
Java-da Bridge Pattern İmplementasiyası
Sadə Bridge Pattern Nümunəsi
Koda bax
// Implementor interface
interface DrawAPI {
void drawCircle(int radius, int x, int y);
}
// Concrete Implementors
class RedCircle implements DrawAPI {
@Override
public void drawCircle(int radius, int x, int y) {
System.out.println("Drawing Circle[ color: red, radius: " + radius + ", x: " + x + ", y: " + y + "]");
}
}
class GreenCircle implements DrawAPI {
@Override
public void drawCircle(int radius, int x, int y) {
System.out.println("Drawing Circle[ color: green, radius: " + radius + ", x: " + x + ", y: " + y + "]");
}
}
// Abstraction
abstract class Shape {
protected DrawAPI drawAPI;
protected Shape(DrawAPI drawAPI) {
this.drawAPI = drawAPI;
}
public abstract void draw();
}
// Refined Abstraction
class Circle extends Shape {
private int x, y, radius;
public Circle(int x, int y, int radius, DrawAPI drawAPI) {
super(drawAPI);
this.x = x;
this.y = y;
this.radius = radius;
}
@Override
public void draw() {
drawAPI.drawCircle(radius, x, y);
}
}
// Client code
public class BridgePatternDemo {
public static void main(String[] args) {
Shape redCircle = new Circle(100, 100, 10, new RedCircle());
Shape greenCircle = new Circle(200, 200, 20, new GreenCircle());
redCircle.draw();
greenCircle.draw();
}
}
Daha Mürəkkəb Bridge Pattern Nümunəsi
Koda bax
// Implementor interface
interface Device {
boolean isEnabled();
void enable();
void disable();
int getVolume();
void setVolume(int volume);
int getChannel();
void setChannel(int channel);
}
// Concrete Implementors
class TV implements Device {
private boolean on = false;
private int volume = 30;
private int channel = 1;
@Override
public boolean isEnabled() {
return on;
}
@Override
public void enable() {
on = true;
System.out.println("TV turned on");
}
@Override
public void disable() {
on = false;
System.out.println("TV turned off");
}
@Override
public int getVolume() {
return volume;
}
@Override
public void setVolume(int volume) {
if (volume > 100) {
this.volume = 100;
} else if (volume < 0) {
this.volume = 0;
} else {
this.volume = volume;
}
System.out.println("TV volume set to " + this.volume);
}
@Override
public int getChannel() {
return channel;
}
@Override
public void setChannel(int channel) {
this.channel = channel;
System.out.println("TV channel set to " + this.channel);
}
}
class Radio implements Device {
private boolean on = false;
private int volume = 20;
private int channel = 1;
@Override
public boolean isEnabled() {
return on;
}
@Override
public void enable() {
on = true;
System.out.println("Radio turned on");
}
@Override
public void disable() {
on = false;
System.out.println("Radio turned off");
}
@Override
public int getVolume() {
return volume;
}
@Override
public void setVolume(int volume) {
if (volume > 100) {
this.volume = 100;
} else if (volume < 0) {
this.volume = 0;
} else {
this.volume = volume;
}
System.out.println("Radio volume set to " + this.volume);
}
@Override
public int getChannel() {
return channel;
}
@Override
public void setChannel(int channel) {
this.channel = channel;
System.out.println("Radio channel set to " + this.channel);
}
}
// Abstraction
abstract class RemoteControl {
protected Device device;
public RemoteControl(Device device) {
this.device = device;
}
public void togglePower() {
if (device.isEnabled()) {
device.disable();
} else {
device.enable();
}
}
public void volumeUp() {
device.setVolume(device.getVolume() + 10);
}
public void volumeDown() {
device.setVolume(device.getVolume() - 10);
}
public void channelUp() {
device.setChannel(device.getChannel() + 1);
}
public void channelDown() {
device.setChannel(device.getChannel() - 1);
}
}
// Refined Abstraction
class AdvancedRemoteControl extends RemoteControl {
public AdvancedRemoteControl(Device device) {
super(device);
}
public void mute() {
device.setVolume(0);
System.out.println("Muted");
}
public void setChannel(int channel) {
device.setChannel(channel);
}
}
// Client code
public class BridgePatternAdvancedDemo {
public static void main(String[] args) {
Device tv = new TV();
Device radio = new Radio();
RemoteControl tvRemote = new RemoteControl(tv);
RemoteControl radioRemote = new RemoteControl(radio);
tvRemote.togglePower();
tvRemote.volumeUp();
tvRemote.channelUp();
radioRemote.togglePower();
radioRemote.volumeDown();
radioRemote.channelDown();
AdvancedRemoteControl advancedTvRemote = new AdvancedRemoteControl(tv);
advancedTvRemote.mute();
advancedTvRemote.setChannel(100);
}
}
Real-World Nümunələr
JDBC API
JDBC API, Bridge pattern-in real-world nümunəsidir:
Koda bax
import java.sql.*;
public class JdbcBridgeExample {
public static void main(String[] args) {
try {
// Load the driver (Concrete Implementor)
Class.forName("com.mysql.jdbc.Driver");
// Create a connection (Abstraction uses Implementor)
Connection connection = DriverManager.getConnection(
"jdbc:mysql://localhost:3306/mydb", "username", "password");
// Create a statement
Statement statement = connection.createStatement();
// Execute query
ResultSet resultSet = statement.executeQuery("SELECT * FROM users");
// Process results
while (resultSet.next()) {
String name = resultSet.getString("name");
String email = resultSet.getString("email");
System.out.println("User: " + name + ", Email: " + email);
}
// Close resources
resultSet.close();
statement.close();
connection.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
Graphics System
Koda bax
// Implementor interface
interface Renderer {
void renderCircle(float radius);
void renderRectangle(float width, float height);
}
// Concrete Implementors
class VectorRenderer implements Renderer {
@Override
public void renderCircle(float radius) {
System.out.println("Drawing a circle of radius " + radius + " using vector graphics");
}
@Override
public void renderRectangle(float width, float height) {
System.out.println("Drawing a rectangle of width " + width + " and height " + height + " using vector graphics");
}
}
class RasterRenderer implements Renderer {
@Override
public void renderCircle(float radius) {
System.out.println("Drawing pixels for a circle of radius " + radius);
}
@Override
public void renderRectangle(float width, float height) {
System.out.println("Drawing pixels for a rectangle of width " + width + " and height " + height);
}
}
// Abstraction
abstract class Shape {
protected Renderer renderer;
public Shape(Renderer renderer) {
this.renderer = renderer;
}
public abstract void draw();
public abstract void resize(float factor);
}
// Refined Abstractions
class Circle extends Shape {
private float radius;
public Circle(Renderer renderer, float radius) {
super(renderer);
this.radius = radius;
}
@Override
public void draw() {
renderer.renderCircle(radius);
}
@Override
public void resize(float factor) {
radius *= factor;
}
}
class Rectangle extends Shape {
private float width;
private float height;
public Rectangle(Renderer renderer, float width, float height) {
super(renderer);
this.width = width;
this.height = height;
}
@Override
public void draw() {
renderer.renderRectangle(width, height);
}
@Override
public void resize(float factor) {
width *= factor;
height *= factor;
}
}
// Client code
public class GraphicsSystemDemo {
public static void main(String[] args) {
Renderer vectorRenderer = new VectorRenderer();
Renderer rasterRenderer = new RasterRenderer();
Shape circle1 = new Circle(vectorRenderer, 5);
Shape circle2 = new Circle(rasterRenderer, 5);
Shape rectangle1 = new Rectangle(vectorRenderer, 10, 5);
Shape rectangle2 = new Rectangle(rasterRenderer, 10, 5);
circle1.draw();
circle2.draw();
rectangle1.draw();
rectangle2.draw();
System.out.println("\nResizing shapes...");
circle1.resize(2);
circle2.resize(2);
rectangle1.resize(0.5f);
rectangle2.resize(0.5f);
circle1.draw();
circle2.draw();
rectangle1.draw();
rectangle2.draw();
}
}
Bridge Pattern-nin Üstünlükləri
- Decoupling: Abstraction və implementation arasında zəif əlaqə (loose coupling) yaradır
- Extensibility: Abstraction və implementation hierarchies-ni ayrı-ayrılıqda genişləndirməyə imkan verir
- Hiding Implementation Details: Client-dən implementation detallarını gizlədir
- Open/Closed Principle: Mövcud kodu dəyişdirmədən yeni abstractions və implementations əlavə etməyə imkan verir
Bridge Pattern-nin Çatışmazlıqları
- Complexity: Kod-un mürəkkəbliyini artırır
- Planning: Pattern-in tətbiqi üçün əvvəlcədən planlaşdırma tələb olunur
- Overhead: Əlavə indirection layer-i performance-a təsir edə bilər
Bridge Pattern-nin İstifadə Sahələri
- Cross-platform Applications: Müxtəlif platformalar üçün tətbiqlər yaratmaq
- Multiple Database Support: Müxtəlif database sistemləri ilə işləmək
- Different UI Implementations: Müxtəlif UI framework-ləri ilə işləmək
- Hardware Abstraction: Hardware detallarını gizlətmək
Bridge Pattern-nin Digər Pattern-lərlə Müqayisəsi
Bridge vs Adapter
- Bridge: Abstraction və implementation arasında körpü yaradır və hər ikisini ayrı-ayrılıqda genişləndirməyə imkan verir
- Adapter: Mövcud interface-ləri uyğunlaşdırır, lakin onları genişləndirmir
Bridge vs Strategy
- Bridge: Abstraction və implementation arasında körpü yaradır
- Strategy: Bir algoritmin müxtəlif variantlarını təqdim edir
Bridge vs Abstract Factory
- Bridge: Abstraction və implementation arasında körpü yaradır
- Abstract Factory: Əlaqəli obyektlərin ailəsini yaratmaq üçün istifadə olunur