我可以做些什么来删除或最小化将提供相同功能和行为的代码重复?
What can I do to remove or minimize this code duplication that will provide the same functionality and behavior?
我有一组派生的 classes,我正在使用一个函数在 class 实例化或创建时自动更新它们的内部 ID 值。最初我在他们的 base 或 superclass 中有这个功能并且它正在工作给我正确的结果。但是,作为一项设计决策,我正在更改此行为。
在第一个版本中,每次构造 Component
对象时,即使子类型不同,附加的数值也会递增。我不想要这种行为。我希望每个 subclass 从 [0]
开始并向上计数...
我移动了执行此计算的函数,将新值附加到成员 string
id 从基础 class 到派生的 classes。然而,这现在正在创建代码重复,并且根据当前的设计,每个未来的 subclass 都必须实现这个功能...
我想要与当前相同的功能和行为,但没有代码重复!
这是我当前的输出,这是我正在寻找的显示 ID 的行为:
Successfully connected Wire_001 to Wire_005
from Wire_001 to Bus_000
Successfully connected Wire_002 to Wire_006
from Wire_002 to Bus_000
Successfully connected Wire_003 to Wire_007
from Wire_003 to Bus_000
Successfully connected Wire_000 to Wire_005
from Wire_000 to Bus_000
Component Wire_000 already exists in Wire_004!
from Wire_000 to Bus_000
Successfully connected Wire_001 to Wire_000
Successfully connected Wire_002 to Wire_001
Successfully connected Wire_003 to Wire_002
Successfully connected Wire_000 to Wire_003
Successfully connected Wire_004 to Wire_008
from Wire_004 to Bus_001
Successfully connected Wire_005 to Wire_009
from Wire_005 to Bus_001
Successfully connected Wire_006 to Wire_010
from Wire_006 to Bus_001
Successfully connected Wire_007 to Wire_011
from Wire_007 to Bus_001
These are my connected components:
Wire_004 has Wire_000
Wire_005 has Wire_001 Wire_000
Wire_006 has Wire_002
Wire_007 has Wire_003
这是我当前的源代码:
main.cpp
#include <exception>
#include "Bus.h"
int main() {
try {
Wire w1, w2, w3, w4;
std::cout << w1.id() << " " << w2.id() << " " << w3.id() << " "<< w4.id() << "\n\n";
Bus<4> b1;
b1.connect(&w1, 0);
b1.connect(&w2, 1);
b1.connect(&w3, 2);
b1.connect(&w4, 3);
b1.connect(&w1, 1); // Valid Connection: same wire to multiple bus wires
b1.connect(&w1, 0); // Invalid Connection: trying to connect a same wire to the same bus wire multiple times...
std::cout << "\n";
Bus<4> b2;
w1.connect(&w2);
w2.connect(&w3);
w3.connect(&w4);
w4.connect(&w1);
std::cout << "\n";
b2.connect(&b1.wire(0), 0);
b2.connect(&b1.wire(1), 1);
b2.connect(&b1.wire(2), 2);
b2.connect(&b1.wire(3), 3);
std::cout << "\nThese are my connected components:\n";
for( size_t i = 0; i < b2.size(); i++ ) {
for (auto& component : b2.myConnections(i)) {
std::cout << "\t" << component->id() << " has ";
auto connections = component->myConnections();
for (auto& c : connections) {
std::cout << c->id() << " ";
}
std::cout << '\n';
}
std::cout << '\n';
}
} catch (const std::exception& e) {
std::cerr << e.what() << std::endl;
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}
Component.h
#pragma once
#include <assert.h>
#include <memory>
#include <array>
#include <list>
#include <iomanip>
#include <iostream>
#include <string>
#include <sstream>
class Component {
protected:
std::string id_ = "";
std::list<std::shared_ptr<Component>> components_;
explicit Component(const std::string& id) : id_{ id } {}
public:
virtual ~Component() {}
std::string& id() { return id_; }
void connect(Component* other) {
for (auto& l : components_) {
if (other->id_ == l->id()) {
std::cout << "Component " << other->id_ << " already exists in " << id_ << "!\n";
return;
}
}
components_.push_back( std::make_shared<Component>( *other ) );
std::cout << "Successfully connected " << other->id() << " to " << id_ << "\n";
}
virtual std::list<std::shared_ptr<Component>> myConnections() { return components_; }
virtual void propagate() {};
};
Wire.h
#pragma once
#include "Component.h"
class Wire : public Component {
private:
public:
explicit Wire(const std::string& name = "Wire") : Component(name) {
updateId();
};
virtual ~Wire() {}
virtual void propagate() override {
return;
}
private:
void updateId() {
static int i = 0;
std::stringstream strValue;
strValue << std::setw(3) << std::setfill('0') << std::to_string(i++);
id_.append("_" + strValue.str());
}
};
Bus.h
#pragma once
#include "Wire.h"
template<size_t BusSize>
class Bus : public Component {
private:
std::array<std::shared_ptr<Wire>, BusSize> bus_interface_;
public:
explicit Bus(const std::string& name = "Bus") : Component(name) {
updateId();
createBus();
}
virtual ~Bus() {}
virtual void propagate() override {
return;
}
void connect(Component* component, size_t index) {
assert(index < BusSize);
assert(component != nullptr);
bus_interface_[index]->connect(component);
std::cout << "\t from " << component->id() << " to " << id_ << "\n";
}
Wire& wire(size_t index) {
assert(index < BusSize);
return *bus_interface_[index].get();
}
std::array<std::shared_ptr<Wire>, BusSize> bus() { return bus_interface_; }
std::list<std::shared_ptr<Component>> myConnections(size_t index) {
assert(index < BusSize);
return bus_interface_[index]->myConnections();
}
size_t size() const { return BusSize; }
private:
void updateId() {
static int i = 0;
std::stringstream strValue;
strValue << std::setw(3) << std::setfill('0') << std::to_string(i++);
id_.append("_" + strValue.str());
}
void createBus() {
size_t i = 0;
for (auto& w : bus_interface_) {
w = std::shared_ptr<Wire>(new Wire);
}
}
};
从两个子class可以看出,它们的成员函数::updateId()
:
void updateId() {
static int i = 0;
std::stringstream strValue;
strValue << std::setw(3) << std::setfill('0') << std::to_string(i++);
id_.append("_" + strValue.str());
}
是我关心的代码重复。我该怎么做才能在保持相同功能和行为的同时消除此代码重复的依赖性?
你可以利用CRTP。添加一个模板化的第二个基地 class 来保存 ID 处理代码。
template <class T>
class ComponentID {
public:
ComponentID(std::string &id_) {
// Same as updateID above
}
};
class Wire: public Component, ComponentID<Wire> {
public:
Wire(const std::string& name = "Wire") : Component(name), ComponentID(id_) {
}
// ...
};
template<size_t BusSize>
class Bus : public Component, ComponentID<Bus<BusSize>> {
public:
explicit Bus(const std::string& name = "Bus") : Component(name), ComponentID(id_) {
createBus();
}
// ...
};
我们将 id_
字段从 Component
基础 class 传递给 ComponentID
构造函数,这样它就可以更新而无需更改访问权限至 id
.
我有一组派生的 classes,我正在使用一个函数在 class 实例化或创建时自动更新它们的内部 ID 值。最初我在他们的 base 或 superclass 中有这个功能并且它正在工作给我正确的结果。但是,作为一项设计决策,我正在更改此行为。
在第一个版本中,每次构造 Component
对象时,即使子类型不同,附加的数值也会递增。我不想要这种行为。我希望每个 subclass 从 [0]
开始并向上计数...
我移动了执行此计算的函数,将新值附加到成员 string
id 从基础 class 到派生的 classes。然而,这现在正在创建代码重复,并且根据当前的设计,每个未来的 subclass 都必须实现这个功能...
我想要与当前相同的功能和行为,但没有代码重复!
这是我当前的输出,这是我正在寻找的显示 ID 的行为:
Successfully connected Wire_001 to Wire_005
from Wire_001 to Bus_000
Successfully connected Wire_002 to Wire_006
from Wire_002 to Bus_000
Successfully connected Wire_003 to Wire_007
from Wire_003 to Bus_000
Successfully connected Wire_000 to Wire_005
from Wire_000 to Bus_000
Component Wire_000 already exists in Wire_004!
from Wire_000 to Bus_000
Successfully connected Wire_001 to Wire_000
Successfully connected Wire_002 to Wire_001
Successfully connected Wire_003 to Wire_002
Successfully connected Wire_000 to Wire_003
Successfully connected Wire_004 to Wire_008
from Wire_004 to Bus_001
Successfully connected Wire_005 to Wire_009
from Wire_005 to Bus_001
Successfully connected Wire_006 to Wire_010
from Wire_006 to Bus_001
Successfully connected Wire_007 to Wire_011
from Wire_007 to Bus_001
These are my connected components:
Wire_004 has Wire_000
Wire_005 has Wire_001 Wire_000
Wire_006 has Wire_002
Wire_007 has Wire_003
这是我当前的源代码:
main.cpp
#include <exception>
#include "Bus.h"
int main() {
try {
Wire w1, w2, w3, w4;
std::cout << w1.id() << " " << w2.id() << " " << w3.id() << " "<< w4.id() << "\n\n";
Bus<4> b1;
b1.connect(&w1, 0);
b1.connect(&w2, 1);
b1.connect(&w3, 2);
b1.connect(&w4, 3);
b1.connect(&w1, 1); // Valid Connection: same wire to multiple bus wires
b1.connect(&w1, 0); // Invalid Connection: trying to connect a same wire to the same bus wire multiple times...
std::cout << "\n";
Bus<4> b2;
w1.connect(&w2);
w2.connect(&w3);
w3.connect(&w4);
w4.connect(&w1);
std::cout << "\n";
b2.connect(&b1.wire(0), 0);
b2.connect(&b1.wire(1), 1);
b2.connect(&b1.wire(2), 2);
b2.connect(&b1.wire(3), 3);
std::cout << "\nThese are my connected components:\n";
for( size_t i = 0; i < b2.size(); i++ ) {
for (auto& component : b2.myConnections(i)) {
std::cout << "\t" << component->id() << " has ";
auto connections = component->myConnections();
for (auto& c : connections) {
std::cout << c->id() << " ";
}
std::cout << '\n';
}
std::cout << '\n';
}
} catch (const std::exception& e) {
std::cerr << e.what() << std::endl;
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}
Component.h
#pragma once
#include <assert.h>
#include <memory>
#include <array>
#include <list>
#include <iomanip>
#include <iostream>
#include <string>
#include <sstream>
class Component {
protected:
std::string id_ = "";
std::list<std::shared_ptr<Component>> components_;
explicit Component(const std::string& id) : id_{ id } {}
public:
virtual ~Component() {}
std::string& id() { return id_; }
void connect(Component* other) {
for (auto& l : components_) {
if (other->id_ == l->id()) {
std::cout << "Component " << other->id_ << " already exists in " << id_ << "!\n";
return;
}
}
components_.push_back( std::make_shared<Component>( *other ) );
std::cout << "Successfully connected " << other->id() << " to " << id_ << "\n";
}
virtual std::list<std::shared_ptr<Component>> myConnections() { return components_; }
virtual void propagate() {};
};
Wire.h
#pragma once
#include "Component.h"
class Wire : public Component {
private:
public:
explicit Wire(const std::string& name = "Wire") : Component(name) {
updateId();
};
virtual ~Wire() {}
virtual void propagate() override {
return;
}
private:
void updateId() {
static int i = 0;
std::stringstream strValue;
strValue << std::setw(3) << std::setfill('0') << std::to_string(i++);
id_.append("_" + strValue.str());
}
};
Bus.h
#pragma once
#include "Wire.h"
template<size_t BusSize>
class Bus : public Component {
private:
std::array<std::shared_ptr<Wire>, BusSize> bus_interface_;
public:
explicit Bus(const std::string& name = "Bus") : Component(name) {
updateId();
createBus();
}
virtual ~Bus() {}
virtual void propagate() override {
return;
}
void connect(Component* component, size_t index) {
assert(index < BusSize);
assert(component != nullptr);
bus_interface_[index]->connect(component);
std::cout << "\t from " << component->id() << " to " << id_ << "\n";
}
Wire& wire(size_t index) {
assert(index < BusSize);
return *bus_interface_[index].get();
}
std::array<std::shared_ptr<Wire>, BusSize> bus() { return bus_interface_; }
std::list<std::shared_ptr<Component>> myConnections(size_t index) {
assert(index < BusSize);
return bus_interface_[index]->myConnections();
}
size_t size() const { return BusSize; }
private:
void updateId() {
static int i = 0;
std::stringstream strValue;
strValue << std::setw(3) << std::setfill('0') << std::to_string(i++);
id_.append("_" + strValue.str());
}
void createBus() {
size_t i = 0;
for (auto& w : bus_interface_) {
w = std::shared_ptr<Wire>(new Wire);
}
}
};
从两个子class可以看出,它们的成员函数::updateId()
:
void updateId() {
static int i = 0;
std::stringstream strValue;
strValue << std::setw(3) << std::setfill('0') << std::to_string(i++);
id_.append("_" + strValue.str());
}
是我关心的代码重复。我该怎么做才能在保持相同功能和行为的同时消除此代码重复的依赖性?
你可以利用CRTP。添加一个模板化的第二个基地 class 来保存 ID 处理代码。
template <class T>
class ComponentID {
public:
ComponentID(std::string &id_) {
// Same as updateID above
}
};
class Wire: public Component, ComponentID<Wire> {
public:
Wire(const std::string& name = "Wire") : Component(name), ComponentID(id_) {
}
// ...
};
template<size_t BusSize>
class Bus : public Component, ComponentID<Bus<BusSize>> {
public:
explicit Bus(const std::string& name = "Bus") : Component(name), ComponentID(id_) {
createBus();
}
// ...
};
我们将 id_
字段从 Component
基础 class 传递给 ComponentID
构造函数,这样它就可以更新而无需更改访问权限至 id
.