Híd programtervezési minta

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
 
Híd LePUS3-ban (legend)

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

  1. Gamma, E, Helm, R, Johnson, R, Vlissides, J: Design Patterns, page 151. Addison-Wesley, 1995

További információk szerkesztés

Az angol Wikikönyvekben
további információk találhatók

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.