桥接模式——组合还是聚合?

发布于 2024-09-09 12:36:45 字数 81 浏览 3 评论 0原文

我正在阅读一些有关设计模式的书籍,有些将抽象和实现之间的关系描述为组合,有些则将其描述为聚合。现在我想知道:这取决于实施吗?就语言而言?或者上下文?

I'm reading some books about Design Patterns and while some describe the relation between the abstraction and the implementation as a composition, some describe it as an aggregation. Now I wonder: is this dependant on the implementation? On the language? Or context?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

定格我的天空 2024-09-16 12:36:51

桥接模式的标准 UML 消除了周围的混乱。下面是一个带有简短示例的解释,以澄清这一点。

对于这段冗长的代码,我们深表歉意,最好的方法是将这段代码复制到 Visual Studio 中以便于理解。

仔细阅读代码末尾的解释

interface ISpeak
{
    void Speak();
}

class DogSpeak : ISpeak
{
    public void Speak()
    {
        Console.WriteLine("Dog Barks");
    }
}
class CatSpeak : ISpeak
{
    public void Speak()
    {
        Console.WriteLine("Cat Meows");
    }
}

abstract class AnimalBridge
{
    protected ISpeak Speech;

    protected AnimalBridge(ISpeak speech)
    {
        this.Speech = speech;
    }

    public abstract void Speak();
}
class Dog : AnimalBridge
{
    public Dog(ISpeak dogSpeak)
        : base(dogSpeak)
    {

    }
    public override void Speak()
    {
        Speech.Speak();
    }
}

class Cat : AnimalBridge
{
    public Cat(ISpeak catSpeak)
        : base(catSpeak)
    {

    }
    public override void Speak()
    {
        Speech.Speak();
    }
}

——ISpeak是机器人Dog和Cat必须实现的抽象
-- 通过引入由 ISpeak 组成的“Animal”桥来解耦 Dog 和 Cat 类
-- Dog 和 Cat 类扩展了 Animal 类,因此与 ISpeak 解耦。

希望这能澄清

Standard UML of Bridge pattern clears out all air around the confusion. Below is an explanation with a brief example to clear the air around this.

Apologies for this lengthy code, best way is to copy this code to Visual Studio to easily understand it.

Read through the explanation written at the end of code

interface ISpeak
{
    void Speak();
}

class DogSpeak : ISpeak
{
    public void Speak()
    {
        Console.WriteLine("Dog Barks");
    }
}
class CatSpeak : ISpeak
{
    public void Speak()
    {
        Console.WriteLine("Cat Meows");
    }
}

abstract class AnimalBridge
{
    protected ISpeak Speech;

    protected AnimalBridge(ISpeak speech)
    {
        this.Speech = speech;
    }

    public abstract void Speak();
}
class Dog : AnimalBridge
{
    public Dog(ISpeak dogSpeak)
        : base(dogSpeak)
    {

    }
    public override void Speak()
    {
        Speech.Speak();
    }
}

class Cat : AnimalBridge
{
    public Cat(ISpeak catSpeak)
        : base(catSpeak)
    {

    }
    public override void Speak()
    {
        Speech.Speak();
    }
}

-- ISpeak is the abstraction that bot Dog and Cat has to implement
-- Decoupled Dog and Cat classes by introducing a bridge "Animal" that is composed of ISpeak
-- Dog and Cat classes extend Animal class and thus are decoupled from ISpeak.

Hope this clarifies

浅浅 2024-09-16 12:36:50

桥接模式必须使用委托(聚合/组合而不是继承)。来自四人帮书籍:

在以下情况下使用桥接模式

* you want to avoid a permanent binding between an abstraction and its implementation. This might be the case, for example, when the implementation must be selected or switched at run-time.

* both the abstractions and their implementations should be extensible by subclassing. In this case, the Bridge pattern lets you combine the different abstractions and implementations and extend them independently.

* changes in the implementation of an abstraction should have no impact on clients; that is, their code should not have to be recompiled.

* (C++) you want to hide the implementation of an abstraction completely from clients. In C++ the representation of a class is visible in the class interface.

* you have a proliferation of classes as shown earlier in the first Motivation diagram. Such a class hierarchy indicates the need for splitting an object into two parts. Rumbaugh uses the term "nested generalizations" [RBP+91] to refer to such class hierarchies.

* you want to share an implementation among multiple objects (perhaps using reference counting), and this fact should be hidden from the client. A simple example is Coplien's String class [Cop92], in which multiple objects can share the same string representation (StringRep).

the bridge pattern must use delegation (aggregation/composition and not inheritance). from the gang-of-four book:

Use the Bridge pattern when

* you want to avoid a permanent binding between an abstraction and its implementation. This might be the case, for example, when the implementation must be selected or switched at run-time.

* both the abstractions and their implementations should be extensible by subclassing. In this case, the Bridge pattern lets you combine the different abstractions and implementations and extend them independently.

* changes in the implementation of an abstraction should have no impact on clients; that is, their code should not have to be recompiled.

* (C++) you want to hide the implementation of an abstraction completely from clients. In C++ the representation of a class is visible in the class interface.

* you have a proliferation of classes as shown earlier in the first Motivation diagram. Such a class hierarchy indicates the need for splitting an object into two parts. Rumbaugh uses the term "nested generalizations" [RBP+91] to refer to such class hierarchies.

* you want to share an implementation among multiple objects (perhaps using reference counting), and this fact should be hidden from the client. A simple example is Coplien's String class [Cop92], in which multiple objects can share the same string representation (StringRep).
再可℃爱ぅ一点好了 2024-09-16 12:36:49

术语“组合物”和“聚集体”表示或多或少相同的事物并且可以互换使用。在描述容器类(例如列表、动态数组、映射和队列)时,聚合可能会更频繁地使用,其中元素都属于同一类型;然而,这两个术语都可以描述根据其他类定义的类,无论这些类型是同质的(全部相同类型)还是异质的(不同类型的对象)。

为了更清楚地说明这一点:

class Car {
    // ...
    private:
        Engine engine;
        Hood hood;
};

// The car is *composed* of an engine and a hood. Hence, composition. You are
// also bringing together (i.e. *aggregating*) an engine and hood into a car.

抽象和实现之间的关系通常意味着继承,而不是组合/聚合;通常,抽象是接口或虚拟基类,实现是实现给定接口的完全具体的类。但是,让事情变得混乱的是,组合/聚合可以是接口的一部分(因为,例如,您可能需要设置/获取用作构建块的对象),并且它们也是一种实现方法(因为您可以使用委托来提供实现中方法的定义)。

为了使这一点更清楚:

interface Car {
    public Engine getEngine();
    public Hood getHood();
    public void drive();
}
// In the above, the fact that a car has these building blocks
// is a part of its interface (the abstraction).

class HondaCivic2010 implements Car {
    public void drive(){ getEngine().drive(); }
    // ...
}
// In the above, composition/delegation is an implementation
// strategy for providing the drive functionality.

既然您已将问题标记为“桥”,我应该指出桥模式的定义是一种使用组合而不是继承来允许多个不同级别的变化的模式。我在大学学到的一个例子......使用继承,您可能会得到类似的结果:

class GoodCharacter;
class BadCharacter;
class Mage;
class Rogue;
class GoodMage : public GoodCharacter, Mage;
class BadMage : public BadCharacter, Mage;
class GoodRogue : public GoodCharacter, Rogue;
class BadRogue : public BadCharacter, Rogue;

如您所见,这种事情变得非常疯狂,并且您会得到数量可笑的类。同样的事情,使用桥接模式,看起来像:

 class Personality;
 class GoodPersonality : public Personality;
 class BadPersonality : public Personality;

 class CharacterClass;
 class Mage : public CharacterClass;
 class Rogue : public CharacterClass;

 class Character {
    public:
        // ...
    private:
        CharacterClass character_class;
        Personality personality;
 };
 // A character has both a character class and a personality.
 // This is a perfect example of the bridge pattern, and we've
 // reduced MxN classes into a mere M+N classes, and we've
 // arguably made the system even more flexible than before.

The terms "composition" and "aggregation" mean more or less the same thing and may be used interchangeably. Aggregation may be used more frequently when describing container classes such as lists, dynamic arrays, maps, and queues where the elements are all of the same type; however, both terms may be found to describe classes defined in terms of other classes, regardless of whether those types are homogenous (all of the same type) or heterogenous (objects of different types).

To make this clearer:

class Car {
    // ...
    private:
        Engine engine;
        Hood hood;
};

// The car is *composed* of an engine and a hood. Hence, composition. You are
// also bringing together (i.e. *aggregating*) an engine and hood into a car.

The relationship between abstraction and implementation typically implies inheritance, rather than composition/aggregation; typically the abstraction is an interface or virtual base class, and the implementation is a fully concrete class that implements the given interface. But, to make things confusing, composition/aggregation can be a part of the interface (because, for example, you may need to set/get the objects that are used as building blocks), and they are also an approach to implementation (because you might use delegation to provide the definition for methods in your implementation).

To make this clearer:

interface Car {
    public Engine getEngine();
    public Hood getHood();
    public void drive();
}
// In the above, the fact that a car has these building blocks
// is a part of its interface (the abstraction).

class HondaCivic2010 implements Car {
    public void drive(){ getEngine().drive(); }
    // ...
}
// In the above, composition/delegation is an implementation
// strategy for providing the drive functionality.

Since you have tagged your question "bridge", I should point out that the definition of the bridge pattern is a pattern where you use composition rather than inheritance to allow for variation at multiple different levels. An example that I learned at college... using inheritance you might have something like:

class GoodCharacter;
class BadCharacter;
class Mage;
class Rogue;
class GoodMage : public GoodCharacter, Mage;
class BadMage : public BadCharacter, Mage;
class GoodRogue : public GoodCharacter, Rogue;
class BadRogue : public BadCharacter, Rogue;

As you can see, this kind of thing goes pretty crazy, and you get a ridiculous number of classes. The same thing, with the bridge pattern, would look like:

 class Personality;
 class GoodPersonality : public Personality;
 class BadPersonality : public Personality;

 class CharacterClass;
 class Mage : public CharacterClass;
 class Rogue : public CharacterClass;

 class Character {
    public:
        // ...
    private:
        CharacterClass character_class;
        Personality personality;
 };
 // A character has both a character class and a personality.
 // This is a perfect example of the bridge pattern, and we've
 // reduced MxN classes into a mere M+N classes, and we've
 // arguably made the system even more flexible than before.
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文