桥接模式:如何定义调用派生类实现的函数



我正在编写一个聚合物模拟代码,该代码使用桥接模式来分离抽象(模拟中涉及的对象(及其实现(如何表示它们,例如每个单体一个粒子、连续网格等(在层次结构中更高级别的其他类上定义的函数。

我想定义一个基本抽象Monomer,它包含了许多调用MonomerImpl实现的方法。比如说,applyDisplacement在空间中移动单体的方法。然而,当我用几个实现MonomerTypeAImplGridMonomerTypeAImplParticles等定义派生抽象MonomerTypeA时,我想调用在层次结构类顶部定义的applyDisplacement,但使用我的单体类的特定实现。

这是我尝试过的一个例子:

class Monomer
{
public:
...
void applyDisplacement(Vector displacement)
{
getImplementation()->applyDisplacement(displacement);
}
private:
std::unique_ptr<MonomerImpl> p_impl;
virtual MonomerImpl* getImplementation();
};
class MonomerImpl
{
public:
...
void applyDisplacement(Vector displacement)
{
for (int i=0; i<positions.size(); i++)
{
positions[i] += displacement;
}
}
private:
std::vector<Vector> positions;
};

和:

class MonomerTypeA : Monomer
{
public:
...
private:
std::unique_ptr<MonomerTypeAImpl> p_impl;
MonomerImpl* getImplementation()
{
return (MonomerImpl*) p_impl.get();
}
};
class MonomerTypeAImpl : MonomerImpl
{
...
}

如果我使用一个虚拟函数getImplementation函数只能返回一个MonomerImpl*指针,那么我就无法实现该实现的任何附加功能。或者,如果我尝试放弃继承,只定义一堆不同的实现,我将有很多代码重复。

有没有两全其美的解决方案?

我的答案将在代码、代码中的一些注释和此处的文本之间进行划分。

首先,代码:

#include <iostream>
#include <memory>
#include <vector>
// Create a pure virtual interface for your MonomerImpls
class MonomerImpl {
public:
virtual ~MonomerImpl() = default;  // Required in non-concrete classes
void applyDisplacement(int displacement) {
std::cout << "From pure virtual interface " << displacement << ":n";
applyDisplacement_Helper(displacement);
}
// Protected so inherited classes can access it freely
protected:
std::vector<int> positions{};
private:
// Helper
virtual void applyDisplacement_Helper([[maybe_unused]] int displacement) = 0;
};
// Public inheritance is what you want a majority of the time
class MonomerTypeAImpl : public MonomerImpl {
public:
MonomerTypeAImpl() = default;
private:
void applyDisplacement_Helper([[maybe_unused]] int displacement) override {
std::cout << "Specialization From Monomer A Impln";
}
};
// Second MonomerImpl child to illlustrate
class MonomerTypeXImpl : public MonomerImpl {
public:
MonomerTypeXImpl() = default;
private:
void applyDisplacement_Helper([[maybe_unused]] int displacement) override {
std::cout << "specialization From Monomer X ImplnYowzan";
}
};
// If you'll have many Monomers, it's better for the base to be abstract
// In cases where this similar operation is being done, NVI (non-virtual
// interface) can be quite helpful.
//
// I just have a Monomer class, and you can feed different objects different
// MonomerImpls to get the desired behavior
class Monomer {
public:
Monomer(MonomerImpl* impl) : p_impl(impl) {}
void applyDisplacement(int displacement) {
p_impl->applyDisplacement(displacement);
}
private:
std::unique_ptr<MonomerImpl> p_impl;
// I got rid of the get_impl() function, it added an extra step for no gain
};
int main() {
MonomerImpl* monoImpl = new MonomerTypeAImpl();
Monomer mono(monoImpl);
mono.applyDisplacement(42);
std::cout << "nn";
Monomer xMono(new MonomerTypeXImpl());
xMono.applyDisplacement(350);
}

输出:

From pure virtual interface:
From Monomer A Impl: 42

From pure virtual interface:
From Monomer X Impl: 350
Yowza

我不得不删除你的Vector类(没有提供(,所以我只是把它改成了int,这样它就可以编译了。所做的改动并不是很大,因为大部分作品已经在那里了。如果您将有许多不同的实现,我的建议是为这些实现创建一个纯虚拟基类。它标准化了接口,并将代码放在它所属的具体类(对象是可声明的(中。正如我在评论中所说,如果许多派生类都在做同样的事情,那么在-VirtualI接口上使用NVI或N可以帮助实现这一点。NVI的一个例子在类别MonomerImpl中。

(NVI背后的思想是基类可调用(公共(函数不是虚拟的。基类,即使是抽象的,也可以做所有孩子都通用的事情,然后调用一个受保护/私有的虚拟函数,允许孩子们做他们的专业工作,而不仅仅是他们的专门工作。调用虚拟函数的顺序自然取决于公共工作(

有了提供的代码,我觉得从Monomer派生根本没有任何收获。如果不同的MonomerImpl*还不够,那么您可能有这样做的理由。再次,我推荐一个抽象基类作为起点。

如果还有问题,我很乐意回答。作为对这个答案的参考,https://refactoring.guru/design-patterns/bridge

您已经有了这个想法,但您的实现有点偏离实际。

如果我使用虚拟函数getImplementation函数只能返回MonomerImpl*指针,那么我就无法实现实现的任何附加功能

更正:您将能够实现额外的功能,但仅限于MonomerImpl类。而且虚拟函数也与继承一起工作,所以要实现这一点,你必须从基类或抽象类(即接口(继承。

问题是,您还没有制作连接Monomer的各种实现的胶水。Monomer和it实现类之间的这种连接可以使用继承或聚合来实现。但在这种情况下,聚合并不理想,因为它是一个"是">CCD_ 19与it实现之间的关系。

例如

#include <iostream>
#include <memory>
class vector
{
};

// design an abstract base class .ie interface with pure virtual functions
// of all the functions that an implementation must define .
// All these functions will be callable from our base class with polymorphism
class monomer_intf
{
virtual auto
do_apply_displacement(vector displacement) -> void
= 0;
};

// monomer is our concrete base class which will help use call our desired
// implementations in the various derived class
class monomer : public monomer_intf
{
// defined because pure virtual functions need to be defined in the derived
// class else the derived class also becomes an abstract class
auto
do_apply_displacement(vector displacement) -> void override
{
// this dispatches to the dynamic class implementation
// ie. the class monmer will point to or reference to
do_apply_displacement(displacement);
}

public:
auto
apply_displacement(vector displacement) -> void
{
// calls the monomer class do_apply_displacement
// which then dispatches to the implementation
do_apply_displacement(displacement);
}
};

// to get our implementation functionality only the virtual or overriden
// function need to be implemented but we can have several functions as pleases
// us
class monomer_impl : public monomer
{
auto
do_apply_displacement(vector displacement) -> void override
{
std::cout << "monomer called do_apply_displacement of monomer_impl n";
}
};

class monomer_type_a : public monomer
{
auto
do_apply_displacement(vector displacement) -> void override
{
std::cout << "monomer called do_apply_displacement of monomer_type_a n";
}
};
class monomer_type_a_impl_grid : public monomer_type_a
{
auto
do_apply_displacement(vector displacement) -> void override
{
std::cout << "monomer called do_apply_displacement of "
"monomer_type_a_impl_grid n";
}
};
class monomer_type_a_impl : public monomer_impl
{
auto
do_apply_displacement(vector displacement) -> void override
{
std::cout
<< "monomer called do_apply_displacement of monomer_type_a_impl n";
}
};

// if we like this style . It simplifies the creation of the implementations 
// and the execution of our need functions
class monomer_abstraction
{
std::unique_ptr<monomer> implementation_;

public:
explicit monomer_abstraction(monomer *inmplementation)
: implementation_{ inmplementation }
{
}

auto
apply_displacement(vector displacement)
{
implementation_->apply_displacement(displacement);
}
};

auto
main() -> int
{
// using stack allocated monomer_type_a_impl_grid
monomer_type_a_impl_grid impl_grid;
monomer &monomer_grid = impl_grid;
monomer_grid.apply_displacement(vector{});

// using heap allocated monomer_impl
auto impl_ = std::make_unique<monomer_impl>();
monomer &monomer = *impl_;
/// using virtual dispach apply_displacement will call the
/// do_apply_displacement of it dynamic type
monomer.apply_displacement(vector{});

// using monomer_abstraction as an abstraction to the implementations
// of need functionalities
auto abstraction
= monomer_abstraction(std::make_unique<monomer_type_a_impl>().release());
abstraction.apply_displacement(vector{});
}

极度干燥是的发展方向

最新更新