首页 > 解决方案 > 如何简化适配器方案?

问题描述

为了说明清楚,我先贴出“如何使用”的代码:

AB.h:

#include <vector>
#include <list>

// execpt they both have children, A & B share nothing in common,
// even children use different containers
struct A {
  int num;
  std::vector<A> children;
};

struct B {
  std::string s;
  float n;
  std::list<B> children;
};

主.cpp:

#include "Node.h"

// handle A & B with the common interface Node
// do not use template, since in practice, print() may be a large library
void print(Node& n) {
  printf("%s\n", n.tell().c_str());
  for (auto& c : n.children()) {
    print(c);
  }
}

////////////////////////////////////////////////////////////////////////////////
int main() {
  A a { .num = 3, .children = { { .num = 7 }, { .num = 8 } } };
  NodeA na(&a); // wrap A with NodeA adapter
  print(na);

  B b {
    .s = "Will", .n = 1,
    .children = { { .s = "Ryu", .n = 5 }, { .s = "Ken", .n = 8 } }
  };
  NodeB nb(&b); // wrap B with NodeB adapter
  print(nb);
}

编译运行:

WilldeMacBook-Pro:testNodes Will$ cc -std=c++11 -lc++ main.cpp Node.cpp
WilldeMacBook-Pro:testNodes Will$ ./a.out
3
7
8
Will1.000000
Ryu5.000000
Ken8.000000

它确实有效,以通用的方式处理不同的 A 和 B,运行时开销很小,并且......简单明了......直到你看到 Node.h:

#include <memory>
#include <sstream>
#include "AB.h"

////////////////////////////////////////////////////////////////////////////////
struct Node;
struct Nodes;
struct NodeIter;
struct NodeIterPtr;

struct Node { // the only interface i care about, other three are "have-to" ones
  virtual std::string tell() = 0;
  virtual Nodes& children() = 0;
};

struct Nodes {
  virtual NodeIterPtr begin() = 0;
  virtual NodeIterPtr end() = 0;
};

struct NodeIter {
  virtual ~NodeIter() {}
  virtual Node& operator*() = 0;
  virtual NodeIter& operator++() = 0;
  virtual bool operator!=(const NodeIter& other) = 0;
};

struct NodeIterPtr {
  NodeIterPtr(NodeIter* p) : ptr(p) {}

  Node& operator*() { return (*ptr).operator*(); }
  NodeIter& operator++() { return (*ptr).operator++(); }
  bool operator!=(const NodeIterPtr& other) {
    return (*ptr).operator!=(*other.ptr);
  }

private:
  std::shared_ptr<NodeIter> ptr;
};

////////////////////////////////////////////////////////////////////////////////
// adapter for A
struct NodeA : public Node {
  NodeA(A* p) : ptr(p) {}
  std::string tell() { return std::to_string(ptr->num); }
  Nodes& children();

private:
  A* ptr;
};

struct NodesA : public Nodes {
  NodesA(std::vector<A>* ns) : nodes(ns) {}

  NodeIterPtr begin();
  NodeIterPtr end();

private:
  std::vector<A>* nodes;
};

struct NodeIterA : public NodeIter {
  NodeIterA(A* p) : ptr(p) {}

  Node& operator*() { static NodeA a(nullptr); a = NodeA(ptr); return a; }
  NodeIter& operator++() { ptr++; return *this; }
  bool operator!=(const NodeIter& other) {
    auto realOther = (const NodeIterA&)(other);
    return ptr != realOther.ptr;
  }

private:
  A* ptr;
};

////////////////////////////////////////////////////////////////////////////////
// adapter for B
struct NodeB : public Node {
  NodeB(B* p) : ptr(p) {}
  std::string tell() { return ptr->s + std::to_string(ptr->n); }
  Nodes& children();

private:
  B* ptr;
};

struct NodesB : public Nodes {
  NodesB(std::list<B>* ns) : nodes(ns) {}

  NodeIterPtr begin();
  NodeIterPtr end();

private:
  std::list<B>* nodes;
};

struct NodeIterB : public NodeIter {
  NodeIterB(std::list<B>::iterator i) : iter(i) {}

  Node& operator*() { static NodeB b(nullptr); b = NodeB(&(*iter)); return b; }
  NodeIter& operator++() { iter++; return *this; }
  bool operator!=(const NodeIter& other) {
    auto realOther = (const NodeIterB&)(other);
    return iter != realOther.iter;
  }

private:
  std::list<B>::iterator iter;
};

和 Node.cpp:

#include "Node.h"

Nodes& NodeA::children() {
  static NodesA c(nullptr);
  c = NodesA(&ptr->children);
  return c;
}

NodeIterPtr NodesA::begin() {
  auto iter = new NodeIterA(&(*nodes->begin()));
  return NodeIterPtr(iter);
}

NodeIterPtr NodesA::end() {
  auto iter = new NodeIterA(&(*nodes->end()));
  return NodeIterPtr(iter);
}

////////////////////////////////////////////////////////////////////////////////
Nodes& NodeB::children() {
  static NodesB c(nullptr);
  c = NodesB(&ptr->children);
  return c;
}

NodeIterPtr NodesB::begin() {
  auto iter = new NodeIterB(nodes->begin());
  return NodeIterPtr(iter);
}

NodeIterPtr NodesB::end() {
  auto iter = new NodeIterB(nodes->end());
  return NodeIterPtr(iter);
}

我真的觉得太复杂了,要实现这么简单的目标。(如果 A 和 B 有多个容器成员,例如学生/员工/门票,那简直就是地狱。) C++ 是为此设计的吗?我什至想到了一些返回基类引用而不是基类指针的奇怪想法。无论如何,我想问的是,有没有办法简化上面的代码?俗话说,“说话便宜,给我看代码”,在谈论任何哲学之前,我更喜欢看到可以直接编译和运行的代码,相同的输出,相同的简单使用方式,但降低了 Node.js 的复杂性。 h/cpp. 谢谢。

标签: c++adapterranged-loops

解决方案


推荐阅读