Híd programtervezési minta
A híd programtervezési minta egy szoftverfejlesztésben használt tervezési minta, mely azt jelenti, hogy "különválasztjuk az absztrakciót az implementációjától, hogy a kettőt függetlenül lehessen variálni."[1] A híd egységbe zárást, aggregációt, és öröklődést használ, hogy a felelősségi köröket különböző osztályokba különítse el.
A híd mintára kétrétegű absztrakcióként is tekinthetünk. Ez általában azt jelenti, hogy adva van két interfész (a híd két "pillére"), az egyik magaszintű művelet(ek)et, a másik alacsonyszintű művelet(ek)et deklarál; és a magasszintű interfész implementációi az alacsonyszintű interfész tetszőleges implementációjával együttműködnek (és azt a konstruktorban veszik át). Ez lehetővé teszi, hogy a rétegek egymástól függetlenül cserélhetők legyenek.
Előfordul, hogy csak egy fix implementáció létezik, ez a minta Pimpl idiómaként is ismert a C++ világban.
A híd minta nem azonos az illesztő (adapter) mintával, bár a híd mintát gyakran valósítják meg az osztály illesztő minta felhasználásával (ld. a lenti példákat).
A híd minta a függőség befecskendezésének (dependency injection) egyik lehetséges módja.
Struktúra
[szerkesztés]- Abstraction (absztrakt osztály)
- definiálja az absztrakt interfészt
- karbantarja az Implementor referenciát.
- RefinedAbstraction (normál osztály)
- kiterjeszti Abstraction által definiált interfészt
- Implementor (interfész)
- definiálja az interfészt az implementation osztályokra
- ConcreteImplementor (normál osztály)
- megvalósítja az Implementor interfészt
Példa
[szerkesztés]Java
[szerkesztés]A következő Java program alakzatok kirajzolásának példáján keresztül illusztrálja a híd mintát.
/** "Implementor" */
interface DrawingAPI {
public void drawCircle(double x, double y, double radius);
}
/** "ConcreteImplementor" 1/2 */
class DrawingAPI1 implements DrawingAPI {
public void drawCircle(double x, double y, double radius) {
System.out.printf("API1.circle at %f:%f radius %f\n", x, y, radius);
}
}
/** "ConcreteImplementor" 2/2 */
class DrawingAPI2 implements DrawingAPI {
public void drawCircle(double x, double y, double radius) {
System.out.printf("API2.circle at %f:%f radius %f\n", x, y, radius);
}
}
/** "Abstraction" */
abstract class Shape {
protected DrawingAPI drawingAPI;
protected Shape(DrawingAPI drawingAPI){
this.drawingAPI = drawingAPI;
}
public abstract void draw(); // low-level
public abstract void resizeByPercentage(double pct); // high-level
}
/** "Refined Abstraction" */
class CircleShape extends Shape {
private double x, y, radius;
public CircleShape(double x, double y, double radius, DrawingAPI drawingAPI) {
super(drawingAPI);
this.x = x; this.y = y; this.radius = radius;
}
// low-level i.e. Implementation specific
public void draw() {
drawingAPI.drawCircle(x, y, radius);
}
// high-level i.e. Abstraction specific
public void resizeByPercentage(double pct) {
radius *= pct;
}
}
/** "Client" */
class BridgePatternExample {
public static void main(String[] args) {
Shape[] shapes = new Shape[] {
new CircleShape(1, 2, 3, new DrawingAPI1()),
new CircleShape(5, 7, 11, new DrawingAPI2()),
};
for (Shape shape : shapes) {
shape.resizeByPercentage(2.5);
shape.draw();
}
}
}
Kimenete:
API1.circle at 1.000000:2.000000 radius 7.5000000 API2.circle at 5.000000:7.000000 radius 27.500000
PHP
[szerkesztés]PHP nyelvű példa.
interface DrawingAPI {
function drawCircle($dX, $dY, $dRadius);
}
class DrawingAPI1 implements DrawingAPI {
public function drawCircle($dX, $dY, $dRadius) {
echo "API1.circle at $dX:$dY radius $dRadius.<br/>";
}
}
class DrawingAPI2 implements DrawingAPI {
public function drawCircle($dX, $dY, $dRadius) {
echo "API2.circle at $dX:$dY radius $dRadius.<br/>";
}
}
abstract class Shape {
protected $oDrawingAPI;
public abstract function draw();
public abstract function resizeByPercentage($dPct);
protected function __construct(DrawingAPI $oDrawingAPI) {
$this->oDrawingAPI = $oDrawingAPI;
}
}
class CircleShape extends Shape {
private $dX;
private $dY;
private $dRadius;
public function __construct($dX, $dY, $dRadius, DrawingAPI $oDrawingAPI) {
parent::__construct($oDrawingAPI);
$this->dX = $dX;
$this->dY = $dY;
$this->dRadius = $dRadius;
}
public function draw() {
$this->oDrawingAPI->drawCircle(
$this->dX,
$this->dY,
$this->dRadius
);
}
public function resizeByPercentage($dPct) {
$this->dRadius *= $dPct;
}
}
class Tester {
public static function main() {
$aShapes = array(
new CircleShape(1, 3, 7, new DrawingAPI1()),
new CircleShape(5, 7, 11, new DrawingAPI2()),
);
foreach ($aShapes as $shape) {
$shape->resizeByPercentage(2.5);
$shape->draw();
}
}
}
Tester::main();
Kimenete:
API1.circle at 1:3 radius 17.5 API2.circle at 5:7 radius 27.5
Scala
[szerkesztés]Scala nyelvű példa.
trait DrawingAPI {
def drawCircle(x: Double, y: Double, radius: Double)
}
class DrawingAPI1 extends DrawingAPI {
def drawCircle(x: Double, y: Double, radius: Double) = println(s"API #1 $x $y $radius")
}
class DrawingAPI2 extends DrawingAPI {
def drawCircle(x: Double, y: Double, radius: Double) = println(s"API #2 $x $y $radius")
}
abstract class Shape(drawingAPI: DrawingAPI) {
def draw()
def resizePercentage(pct: Double)
}
class CircleShape(x: Double, y: Double, var radius: Double, drawingAPI: DrawingAPI)
extends Shape(drawingAPI: DrawingAPI) {
def draw() = drawingAPI.drawCircle(x, y, radius)
def resizePercentage(pct: Double) { radius *= pct }
}
object BridgePatternExample {
def main(args: Array[String]) {
Seq (
new CircleShape(1, 3, 5, new DrawingAPI1),
new CircleShape(4, 5, 6, new DrawingAPI2)
) foreach { x =>
x.resizePercentage(3)
x.draw()
}
}
}
Kapcsolódó szócikkek
[szerkesztés]Jegyzetek
[szerkesztés]- ↑ Gamma, E, Helm, R, Johnson, R, Vlissides, J: Design Patterns, page 151. Addison-Wesley, 1995
További információk
[szerkesztés]- Bridge in UML and in LePUS3 (a formal modelling language)
- C# Design Patterns: The Bridge Pattern. Sample Chapter From: James W. Cooper. C# Design Patterns: A Tutorial. Addison-Wesley. ISBN 0-201-84453-2
Fordítás
[szerkesztés]Ez a szócikk részben vagy egészben a Bridge pattern című angol Wikipédia-szócikk ezen változatának fordításán alapul. Az eredeti cikk szerkesztőit annak laptörténete sorolja fel. Ez a jelzés csupán a megfogalmazás eredetét és a szerzői jogokat jelzi, nem szolgál a cikkben szereplő információk forrásmegjelöléseként.