Jump to content

Узор моста

Шаблон моста — это шаблон проектирования , используемый в разработке программного обеспечения , который предназначен для «отделения абстракции от ее реализации , чтобы они могли изменяться независимо» , представленный «Бандой четырех» . [1] Мост разные использует инкапсуляцию , агрегацию и может использовать наследование для разделения обязанностей на классы .

Когда класс часто меняется, возможности объектно-ориентированного программирования становятся очень полезными, поскольку изменения в можно коде программы легко внести с минимальными предварительными знаниями о программе. Шаблон моста полезен, когда и класс, и то, что он делает, часто меняются. Сам класс можно рассматривать как абстракцию , а то, что класс может делать, как реализацию . Шаблон моста также можно рассматривать как два уровня абстракции.

Когда существует только одна фиксированная реализация, этот шаблон известен как идиома Pimpl в мире C++ .

Шаблон моста часто путают с шаблоном адаптера , и он часто реализуется с использованием шаблона адаптера объекта ; например, в коде Java ниже.

Вариант: реализацию можно еще больше отделить, отложив присутствие реализации до момента использования абстракции.

Шаблон проектирования Bridge — один из двадцати трех известных шаблонов проектирования GoF , которые описывают, как решать повторяющиеся проблемы проектирования для разработки гибкого и многократно используемого объектно-ориентированного программного обеспечения, то есть объектов, которые легче реализовать, изменить, протестировать и повторное использование. [1]

Какие проблемы может решить шаблон проектирования Bridge? [2]

  • Абстракция и ее реализация должны определяться и расширяться независимо друг от друга.
  • Следует избегать привязки во время компиляции между абстракцией и ее реализацией, чтобы реализацию можно было выбрать во время выполнения.

При использовании подклассов разные подклассы реализуют абстрактный класс по-разному. Но реализация привязана к абстракции во время компиляции и не может быть изменена во время выполнения.

Какое решение описывает шаблон проектирования Bridge?

  • Отделить абстракцию ( Abstraction) от его реализации ( Implementor), поместив их в отдельные иерархии классов.
  • Внедрить Abstraction с точки зрения (путем делегирования) Implementor объект.

Это позволяет настроить Abstraction с Implementor объект во время выполнения.
См. также класс Unified Modeling Language и диаграмму последовательности ниже.

Структура

[ редактировать ]

Класс UML и диаграмма последовательности

[ редактировать ]
Пример класса UML и диаграммы последовательности для шаблона проектирования Bridge. [3]

В приведенной выше диаграмме классов Unified Modeling Language абстракция ( Abstraction) не реализуется, как обычно, в единой иерархии наследования. Вместо этого существует одна иерархия для абстракция ( Abstraction) и отдельную иерархию для ее реализации ( Implementor), что делает их независимыми друг от друга. Abstraction интерфейс ( operation()) реализуется посредством (путем делегирования) тот Implementor интерфейс ( imp.operationImp()).
Диаграмма UML последовательности показывает взаимодействие во время выполнения: Abstraction1 объект делегирует реализацию Implementor1 объект (путем вызова operationImp() на Implementor1), который выполняет операцию и возвращается в Abstraction1.

Диаграмма классов

[ редактировать ]

Абстракция (абстрактный класс)
определяет абстрактный интерфейс
поддерживает ссылку на реализацию.
RefinedAbstraction (обычный класс)
расширяет интерфейс, определенный абстракцией
Реализация (интерфейс)
определяет интерфейс для классов реализации
ConcreteImplementor (обычный класс)
реализует интерфейс Implementor
Мост в LePUS3 ( легенда )

Шаблон моста объединяет объекты в древовидную структуру. Он отделяет абстракцию от реализации. Здесь абстракция представляет клиента, из которого будут вызываться объекты. Ниже приведен пример, реализованный на C#.

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

public class Bridge1 : IBridge
{
    public void Function1()
    {
        Console.WriteLine("Bridge1.Function1");
    }

    public void Function2()
    {
        Console.WriteLine("Bridge1.Function2");
    }
}

public class Bridge2 : IBridge
{
    public void Function1()
    {
        Console.WriteLine("Bridge2.Function1");
    }

    public void Function2()
    {
        Console.WriteLine("Bridge2.Function2");
    }
}

public interface IAbstractBridge
{
    void CallMethod1();
    void CallMethod2();
}

public class AbstractBridge : IAbstractBridge
{
    public IBridge bridge;

    public AbstractBridge(IBridge bridge)
    {
        this.bridge = bridge;
    }

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

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

Классы Bridge — это реализация, которая использует ту же интерфейсно-ориентированную архитектуру для создания объектов. С другой стороны, абстракция берет экземпляр класса реализации и запускает его метод. Таким образом, они полностью отделены друг от друга.

Кристалл

[ редактировать ]
abstract class DrawingAPI
  abstract def draw_circle(x : Float64, y : Float64, radius : Float64)
end

class DrawingAPI1 < DrawingAPI
  def draw_circle(x : Float, y : Float, radius : Float)
    "API1.circle at #{x}:#{y} - radius: #{radius}"
  end
end

class DrawingAPI2 < DrawingAPI
  def draw_circle(x : Float64, y : Float64, radius : Float64)
    "API2.circle at #{x}:#{y} - radius: #{radius}"
  end
end

abstract class Shape
  protected getter drawing_api : DrawingAPI

  def initialize(@drawing_api)
  end

  abstract def draw
  abstract def resize_by_percentage(percent : Float64)
end

class CircleShape < Shape
  getter x : Float64
  getter y : Float64
  getter radius : Float64

  def initialize(@x, @y, @radius, drawing_api : DrawingAPI)
    super(drawing_api)
  end

  def draw
    @drawing_api.draw_circle(@x, @y, @radius)
  end

  def resize_by_percentage(percent : Float64)
    @radius *= (1 + percent/100)
  end
end

class BridgePattern
  def self.test
    shapes = [] of Shape
    shapes << CircleShape.new(1.0, 2.0, 3.0, DrawingAPI1.new)
    shapes << CircleShape.new(5.0, 7.0, 11.0, DrawingAPI2.new)

    shapes.each do |shape|
      shape.resize_by_percentage(2.5)
      puts shape.draw
    end
  end
end

BridgePattern.test

Выход

API1.circle at 1.0:2.0 - radius: 3.075
API2.circle at 5.0:7.0 - radius: 11.275
#include <iostream>
#include <string>
#include <vector>


class DrawingAPI {
  public:
    virtual ~DrawingAPI() = default;
    virtual std::string DrawCircle(float x, float y, float radius) const = 0;
};

class DrawingAPI01 : public DrawingAPI {
  public:
    std::string DrawCircle(float x, float y, float radius) const override {
      return "API01.circle at " + std::to_string(x) + ":" + std::to_string(y) +
        " - radius: " + std::to_string(radius); 
    }
};

class DrawingAPI02 : public DrawingAPI {
  public:
    std::string DrawCircle(float x, float y, float radius) const override {
      return "API02.circle at " + std::to_string(x) + ":" + std::to_string(y) +
        " - radius: " + std::to_string(radius); 
    }
};

class Shape {
  public:
    Shape(const DrawingAPI& drawing_api) : drawing_api_(drawing_api) {}
    virtual ~Shape() = default;

    virtual std::string Draw() const = 0;
    virtual float ResizeByPercentage(const float percent) = 0;

  protected:
    const DrawingAPI& drawing_api_;
};

class CircleShape: public Shape {
  public:    
    CircleShape(float x, float y, float radius, const DrawingAPI& drawing_api)
      : Shape(drawing_api), x_(x), y_(y), radius_(radius) {}

    std::string Draw() const override {
        return drawing_api_.DrawCircle(x_, y_, radius_);
    }

    float ResizeByPercentage(const float percent) override {
      return radius_ *= (1.0f + percent/100.0f);
    }
  
  private:
    float x_, y_, radius_;
};

int main(int argc, char** argv) {
  const DrawingAPI01 api1{};
  const DrawingAPI02 api2{};
  std::vector<CircleShape> shapes {
    CircleShape{1.0f, 2.0f, 3.0f, api1},
    CircleShape{5.0f, 7.0f, 11.0f, api2}
  }; 

  for (auto& shape: shapes) {
    shape.ResizeByPercentage(2.5);
    std::cout << shape.Draw() << std::endl;
  }

  return 0;
}

Выход:

API01.circle at 1.000000:2.000000 - radius: 3.075000
API02.circle at 5.000000:7.000000 - radius: 11.275000

Следующая программа Java определяет банковский счет, который отделяет операции со счетом от регистрации этих операций.

// Logger has two implementations: info and warning
@FunctionalInterface
interface Logger {
    void log(String message);
    
    static Logger info() {
        return message -> System.out.println("info: " + message);
    }
    static Logger warning() {
        return message -> System.out.println("warning: " + message);
    }
}

abstract class AbstractAccount {
    private Logger logger = Logger.info();
    
    public void setLogger(Logger logger) {
        this.logger = logger;
    }
    
    // the logging part is delegated to the Logger implementation
    protected void operate(String message, boolean result) {
        logger.log(message + " result " + result);
    }
}

class SimpleAccount extends AbstractAccount {
    private int balance;
    
    public SimpleAccount(int balance) {
        this.balance = balance;
    }
    
    public boolean isBalanceLow() {
        return balance < 50;
    }
    
    public void withdraw(int amount) {
        boolean shouldPerform = balance >= amount;
        if (shouldPerform) {
            balance -= amount;
        }
        operate("withdraw " + amount, shouldPerform);
    }
}

public class BridgeDemo {
    public static void main(String[] args) {
        SimpleAccount account = new SimpleAccount(100);
        account.withdraw(75);
        
        if (account.isBalanceLow()) {
            // you can also change the Logger implementation at runtime
            account.setLogger(Logger.warning());
        }
        
        account.withdraw(10);
        account.withdraw(100);
    }
}

Он выведет:

info: withdraw 75 result true
warning: withdraw 10 result true
warning: withdraw 100 result false
interface DrawingAPI
{
    function drawCircle($x, $y, $radius);
}

class DrawingAPI1 implements DrawingAPI
{
    public function drawCircle($x, $y, $radius)
    {
        echo "API1.circle at $x:$y radius $radius.\n";
    }
}

class DrawingAPI2 implements DrawingAPI
{
    public function drawCircle($x, $y, $radius)
    {
        echo "API2.circle at $x:$y radius $radius.\n";
    }
}

abstract class Shape
{
    protected $drawingAPI;

    public abstract function draw();
    public abstract function resizeByPercentage($pct);

    protected function __construct(DrawingAPI $drawingAPI)
    {
        $this->drawingAPI = $drawingAPI;
    }
}

class CircleShape extends Shape
{
    private $x;
    private $y;
    private $radius;

    public function __construct($x, $y, $radius, DrawingAPI $drawingAPI)
    {
        parent::__construct($drawingAPI);
        $this->x = $x;
        $this->y = $y;
        $this->radius = $radius;
    }

    public function draw()
    {
        $this->drawingAPI->drawCircle($this->x, $this->y, $this->radius);
    }

    public function resizeByPercentage($pct)
    {
        $this->radius *= $pct;
    }
}

class Tester
{
    public static function main()
    {
        $shapes = array(
            new CircleShape(1, 3, 7,  new DrawingAPI1()),
            new CircleShape(5, 7, 11, new DrawingAPI2()),
        );

        foreach ($shapes as $shape) {
            $shape->resizeByPercentage(2.5);
            $shape->draw();
        }
    }
}

Tester::main();

Выход:

API1.circle at 1:3 radius 17.5
API2.circle at 5:7 radius 27.5
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()			
      }	
  }
}
"""
Bridge pattern example.
"""
from abc import ABCMeta, abstractmethod


NOT_IMPLEMENTED = "You should implement this."


class DrawingAPI:
    __metaclass__ = ABCMeta

    @abstractmethod
    def draw_circle(self, x, y, radius):
        raise NotImplementedError(NOT_IMPLEMENTED)


class DrawingAPI1(DrawingAPI):
    def draw_circle(self, x, y, radius):
        return f"API1.circle at {x}:{y} - radius: {radius}"


class DrawingAPI2(DrawingAPI):
    def draw_circle(self, x, y, radius):
        return f"API2.circle at {x}:{y} - radius: {radius}"


class DrawingAPI3(DrawingAPI):
    def draw_circle(self, x, y, radius):
        return f"API3.circle at {x}:{y} - radius: {radius}"


class Shape:
    __metaclass__ = ABCMeta

    drawing_api = None
    def __init__(self, drawing_api):
        self.drawing_api = drawing_api

    @abstractmethod
    def draw(self):
        raise NotImplementedError(NOT_IMPLEMENTED)

    @abstractmethod
    def resize_by_percentage(self, percent):
        raise NotImplementedError(NOT_IMPLEMENTED)


class CircleShape(Shape):
    def __init__(self, x, y, radius, drawing_api):
        self.x = x
        self.y = y
        self.radius = radius
        super(CircleShape, self).__init__(drawing_api)


    def draw(self):
        return self.drawing_api.draw_circle(self.x, self.y, self.radius)

    def resize_by_percentage(self, percent):
        self.radius *= 1 + percent / 100


class BridgePattern:
    @staticmethod
    def test():
        shapes = [
            CircleShape(1.0, 2.0, 3.0, DrawingAPI1()),
            CircleShape(5.0, 7.0, 11.0, DrawingAPI2()),
            CircleShape(5.0, 4.0, 12.0, DrawingAPI3()),
        ]

        for shape in shapes:
            shape.resize_by_percentage(2.5)
            print(shape.draw())


BridgePattern.test()

См. также

[ редактировать ]
  1. ^ Jump up to: а б Гамма, Эрих ; Хелм, Ричард; Джонсон, Ральф ; Влиссидес, Джон (1994). Шаблоны проектирования: элементы объектно-ориентированного программного обеспечения многократного использования . Аддисон-Уэсли. п. 151 . ISBN  0-201-63361-2 .
  2. ^ «Шаблон проектирования моста — проблема, решение и применимость» . w3sDesign.com . Проверено 12 августа 2017 г.
  3. ^ «Шаблон проектирования моста — структура и сотрудничество» . w3sDesign.com . Проверено 12 августа 2017 г.
[ редактировать ]
Arc.Ask3.Ru: конец переведенного документа.
Arc.Ask3.Ru
Номер скриншота №: 6cca04ac9f89f3c7de23af30116ee9de__1699044060
URL1:https://arc.ask3.ru/arc/aa/6c/de/6cca04ac9f89f3c7de23af30116ee9de.html
Заголовок, (Title) документа по адресу, URL1:
Bridge pattern - Wikipedia
Данный printscreen веб страницы (снимок веб страницы, скриншот веб страницы), визуально-программная копия документа расположенного по адресу URL1 и сохраненная в файл, имеет: квалифицированную, усовершенствованную (подтверждены: метки времени, валидность сертификата), открепленную ЭЦП (приложена к данному файлу), что может быть использовано для подтверждения содержания и факта существования документа в этот момент времени. Права на данный скриншот принадлежат администрации Ask3.ru, использование в качестве доказательства только с письменного разрешения правообладателя скриншота. Администрация Ask3.ru не несет ответственности за информацию размещенную на данном скриншоте. Права на прочие зарегистрированные элементы любого права, изображенные на снимках принадлежат их владельцам. Качество перевода предоставляется как есть. Любые претензии, иски не могут быть предъявлены. Если вы не согласны с любым пунктом перечисленным выше, вы не можете использовать данный сайт и информация размещенную на нем (сайте/странице), немедленно покиньте данный сайт. В случае нарушения любого пункта перечисленного выше, штраф 55! (Пятьдесят пять факториал, Денежную единицу (имеющую самостоятельную стоимость) можете выбрать самостоятельно, выплаичвается товарами в течение 7 дней с момента нарушения.)