Modern C++ Design Pattern/Chatper 6. 어댑터
created : 2020-04-07T11:44:17+00:00
modified : 2020-09-26T14:19:03+00:00
Adapter Pattern
- We use a example case, drawiing geometric shape.
struct Point { int x, y; }; struct Line{ Point start, end; }; struct VectorObject { virtual std::vector<Line>::iterator begin() = 0; virtual std::vector<Line>::iterator end() = 0; }; struct VectorRectangle : VectorObject { VectorRectangle(int x, int y, int width, int height) { lines.emplace_back(Line{ Point{x, y}, Point{x + width, y} }); lines.emplace_back(Line{ Point{x + width, y}, Point {x + width, y + height} }); lines.emplace_back(Line{ Point{x,y}, Point{x, y + height} }); lines.emplace_back(Line{ Point{ x, y + height }, Point {x + width, y + height} }); } std::vecotr<Line>::iterator begin() override { return lines.begin(); } std::vector<Line>::iterator end() override { return lines.end(); } private: std::vector<Line> lines; }; void DrawPoints(CPaintDC& dc, std::vector<Point>::iterator start, std::vector<Point>::iterator end) { for (auto i = start; i != end; ++i) dc.SetPixel(i->x, i->y , 0); }
Adapter
- Let’s draw a few rectangles.
vector<shared_ptr<VectorObject>> vectorObjects{
make_shared<VectorRectangle>(10, 10, 100, 100),
make_shared<VectorRectangle>(30, 30, 60, 60)
}
struct LineToPointAdapter
{
typedef vector<Point> Points;
LineToPointAdapter(Line& line);
virtual Points::iterator begin() { return points.begin(); }
virtual Points::iterator end() { return points.end(); }
private:
Points points;
};
LineToPointAdapter::LineToPointAdapter(Line& line)
{
int left = min(line.start.x, line.end.x);
int right = max(line.start.x, line.end.x);
int top = min(line.start.y, line.end.y);
int bottom = max(line.start.y, line.end.y);
int dx = right - left;
int dy = line.end.y - line.start.y;
if (dx == 0)
{
for (int y = top; y <= bottom; ++y)
{
points.emplace_back(Point{ left, y });
}
}
else if (dy == 0)
{
for (int x = left; x <= right; ++x)
{
points.emplace_back(Point{ x, top });
}
}
}
for (auto& obj : vectorObjects)
{
for (auto& line : *obj)
{
LineToPointAdapter lpo{ line };
DrawPoints(dc, lpo.begin(), lpo.end());
}
}
Temporary Adapter
- How about above method is called in every display update despite no change?
-
One of the solutions is to use cache.
vector<Point> points; for (auto& o : vectorObjects) { for (auto& l : *o) { LineToPointAdapter lpo{ l }; for (auto& p : lp) points.push_back(p); } }
-
Of course, this solution cause another problem. That is original vectorOjbects is changed.
struct Point { int x, y; friend std:: size_t hash_value(const POint& obj) { std::size_t send = 0x825C696F; boost::hash_combine(seed, obj.x); boost::hash_combine(seed, obj.y); return seed; } }; struct Line { Point start, end; friend std::size_t hash_value(const Line& obj) { std::size_t seed = 0x719E6B16; boost::hash_combine(seed, obj.start); boost::hash_combine(seed, obj.end); return seed; } }; static map<size_t, Points> cache; virtual Points::iterator begin() { return cache[line_hash].begin(); } virtual Points::iterator end() { return cache[line_hash].end(); } LineToPointCachingAdapter(Line& line){ static boost::hash<Line> hash; line_hash = hash(line); if (cache.find(line_hash) != cache.end()) return; Points points; /* before code */ /* remove before cached point */ cache[line_hash] = points; }
-