Főmenü megnyitása

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ön választjuk az absztrakciót az implementációjától, azért 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és használ, hogy a felelősségi köröket különböző osztályokba különítse el.

Amikor egy osztály gyakran változik, az objektumorientált programozás jellemzői nagyon hasznossá válnak, mert a változások a program forráskódjában könnyen elvégezhetők a korábbi programról való minimális tudással . A híd minta akkor hasznos, ha mind az osztály, mind az általa végzett műveletek gyakran változnak. Az osztályra, mint implementációra gondolhatunk, és amit az osztály csinál, arra pedig mint absztrakcióra. A híd mintára továbbá, mint kétrétegű absztrakcióra is tekinthetünk.

Amikor csak egy fix implementáció létezik, ezt a mintát Pimpl idiómaként is ismert a C++ világban.

A híd mintát gyakran keverik az illesztő mintával. Valójában, a híd mintát gyakran valósítják meg az osztály illesztő minta használatával, például a lenti Java kódban.

Variáns: Az implementáció még jobban külön választható a megvalósítás elhalasztásával attól a ponttól, ahol az absztrakció majd hasznosulni fog.

StruktúraSzerkeszté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éldaSzerkesztés

C#Szerkesztés

A híd minta objektumokat állít elő fa struktúrában. Különválasztja az absztrakciót az implementációtól. Itt az absztrakció képviseli a klienst, ahonnan az objektumot hívni fogják. Nézzük például a következő C# példát.

//IVSR: Bridge pattern example
# region The Implementation

    // Helps in providing truly decoupled architecture
    public interface IBridge
    {
        void Function1();
        void Function2();
    }

    public class Bridge1 : IBridge
    {

        #region IBridge Members

        public void Function1()
        {
            throw new NotImplementedException();
        }

        public void Function2()
        {
            throw new NotImplementedException();
        }

        #endregion
    }

    public class Bridge2 : IBridge
    {
        #region IBridge Members

        public void Function1()
        {
            throw new NotImplementedException();
        }

        public void Function2()
        {
            throw new NotImplementedException();
        }

        #endregion
    }
    # endregion

    # region Abstraction
    public interface IAbstractBridge
    {
        void CallMethod1();
        void CallMethod2();
    }

    public class AbstractBridge : IAbstractBridge 
    {
        public IBridge bridge;

        public AbstractBridge(IBridge bridge)
        {
            this.bridge = bridge;
        }
        #region IAbstractBridge Members

        public void CallMethod1()
        {
            this.bridge.Function1();
        }

        public void CallMethod2()
        {
            this.bridge.Function2();
        }

        #endregion
    }
    # endregion

Ahogy látható a Brigde osztályok az implementáció, melyek ugyanazt az interfészt orientált architektúrát használják objektum létrehozásra. Másfelől az absztrakció fogja az implementáció egy fázisát és végrehajtja rajta az ő metódusát. Ez teljesen különválasztja az egyiket a másiktól.

JavaSzerkesztés

A következő Java (SE 6) program egy 'shape' (alakzat) példá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 BridgePattern {
    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

PHPSzerkeszté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

ScalaSzerkeszté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 BridgePattern {
  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ócikkekSzerkesztés

JegyzetekSzerkesztés

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

További információkSzerkesztés

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

FordításSzerkeszté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.

Sablon:Programtervezési minták