本例来自于Design Pattern in Modern C++一书的适配器模式一节。但是作者的代码是基于MFC绘图的。MFC绑定Windows平台,在Mac和Linux平台上无法使用。本人使用OpenCV重写绘图部分。运行成功。
但是有点值得注意的是,本文中Drawer的draw方法不是一个回调方法。所以本例中的LineToCacheAdapter类,其实作用不大,MFC在CDialog类或者CView类隐藏后再次显示时,可能会调用OnPaint回调方法重绘窗体。所以缓存效果很明显,就是减少无必要的Points计算。
但是本例使用的OpenCV,没有找到重绘窗体的回调。所以不需要刷新窗体。基本上缓存意义不大,除非你画了两条一模一样的线。我的意思是起点和终点相同。
例子的思路其实也很简单。
把原先不能接收线对象的方法,改用LineToPointAdapter进行适配,适配成点集合,这样就可以画点了。
程序目录结构如下,
image.png
test/CMakeLists.txt
cmake_minimum_required(VERSION 2.6)
project(adapter_caching)
set(CMAKE_CXX_STANDARD 20)
add_definitions(-g)
find_package(Boost REQUIRED COMPONENTS
system
filesystem
serialization
program_options
thread
)
find_package(OpenCV REQUIRED )
find_package(glog REQUIRED)
include_directories(${Boost_INCLUDE_DIRS} /usr/local/include /usr/local/include/opencv4 /usr/local/iODBC/include /opt/snowflake/snowflakeodbc/include/ ${CMAKE_CURRENT_SOURCE_DIR}/../../ ${CMAKE_CURRENT_SOURCE_DIR}/../include/ ${CMAKE_CURRENT_SOURCE_DIR}/../../../include/)
LINK_DIRECTORIES(/usr/local/lib /usr/local/iODBC/lib /opt/snowflake/snowflakeodbc/lib/universal)
file( GLOB APP_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/*.cpp ${CMAKE_CURRENT_SOURCE_DIR}/../impl/*.cpp ${CMAKE_CURRENT_SOURCE_DIR}/*.h ${CMAKE_CURRENT_SOURCE_DIR}/*.cpp ${CMAKE_CURRENT_SOURCE_DIR}/../../../include/death_handler/impl/*.cpp)
foreach( sourcefile ${APP_SOURCES} )
file(RELATIVE_PATH filename ${CMAKE_CURRENT_SOURCE_DIR} ${sourcefile})
string(FIND "${filename}" "test.cpp" "TEMP")
if( NOT "${TEMP}" STREQUAL "-1" )
string(REPLACE ".cpp" "" file ${filename})
add_executable(${file} ${APP_SOURCES})
target_link_libraries(${file} ${Boost_LIBRARIES} ${OpenCV_LIBS})
target_link_libraries(${file} glog::glog ssl crypto libgtest.a libgmock.a iodbc iodbcinst libnanodbc.a pthread)
endif()
endforeach( sourcefile ${APP_SOURCES})
test/rect_draw_test.cpp
#include "death_handler/death_handler.h"
#include
#include "rect_draw_cache.hpp"
#include
#include
int main(int argc, char** argv) {
FLAGS_log_dir = "./";
FLAGS_alsologtostderr = true;
// 日志级别 INFO, WARNING, ERROR, FATAL 的值分别为0、1、2、3
FLAGS_minloglevel = 0;
Debug::DeathHandler dh;
google::InitGoogleLogging("./logs.log");
testing::InitGoogleTest(&argc, argv);
int ret = RUN_ALL_TESTS();
return ret;
}
GTEST_TEST(MultitonTests, Multiton) {
DrawableObjects objs {
std::make_shared(10,10,100,100),
std::make_shared(30,30,60,60)
};
Drawer d{objs};
d.draw();
d.wait_to_dispose();
}
include/geometry.h
#ifndef _FREDRIC_GEOMETRY_H_
#define _FREDRIC_GEOMETRY_H_
#include
struct Point {
int x, y;
friend std::size_t hash_value(Point const& obj) {
std::size_t seed = 0x725C686F;
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(Line const& obj) {
std::size_t seed = 0x719E6B16;
boost::hash_combine(seed, obj.start);
boost::hash_combine(seed, obj.end);
return seed;
}
};
struct VectorObject {
virtual std::vector::iterator begin() = 0;
virtual std::vector::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::vector::iterator begin() {
return lines.begin();
}
std::vector::iterator end() {
return lines.end();
}
private:
std::vector lines;
};
#endif
include/rect_draw_cache.hpp
#ifndef _FREDRIC_RECT_DRAW_CACHE_HPP_
#define _FREDRIC_RECT_DRAW_CACHE_HPP_
#include "geometry.h"
#include
#include
#include
#include
#include
程序输出如下,
image.png
image.png