我正在阅读一些关于设计模式的书籍,虽然有些书将抽象和实现之间的关系描述为组合,但有些书将其描述为聚合。现在我想知道:这是否取决于实现?关于语言?还是语境?
3 回答
术语“组合”和“聚合”或多或少意味着相同的事物,并且可以互换使用。在描述容器类(如列表、动态数组、映射和队列,其中元素都是相同类型)时,可能会更频繁地使用聚合;然而,这两个术语都可以用来描述根据其他类定义的类,无论这些类型是同质的(都是相同类型的)还是异质的(不同类型的对象)。
为了更清楚地说明这一点:
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.
桥接模式必须使用委托(聚合/组合而不是继承)。来自四人组的书:
在以下情况下使用桥接模式
* 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).
Bridge 模式的标准 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 解耦。
希望这可以澄清