设计模式-适配器模式

Adapter

适配器 (Adapter/Wrapper) 是一种特殊对象,可以转换对象接口,使两个不兼容的接口能够协同工作

  • 实现无法修改的类(第三方、 遗留系统或者存在众多已有依赖的类)与现有类兼容
  • 优点:提高代码可复用性,系统接口解耦
  • 缺点:维护适配器会增加复杂度,特别是适配接口不断变动情况

CPP

基本结构

Member Full Name Description
被适配者 Adaptee 被适配的组件
目标接口 Target 客户端期望的接口规范
适配器 Adapter 调用被适配者实现目标接口

UML结构图

实现步骤

例如: 有一个第三方库,内部采用邻接矩阵表示图,现在希望用更现代化的接口,基于类封装图数据

  1. 被适配者
1
2
3
4
5
6
7
8
9
10
11
12
13
// legacy_graph.h
class LegacyGraph {
private:
int** adjacencyMatrix; // 邻接矩阵
int numVertices; // 顶点数

public:
LegacyGraph(int vertices);
~LegacyGraph();

void addEdge(int src, int dest, int weight);
int computeShortestPath(int start, int end);
};
  1. 定义目标接口
1
2
3
4
5
6
7
8
9
10
11
12
13
// graph_interface.h
class Graph {
public:
struct Edge {
string from;
string to;
int weight;
};

virtual void addEdge(const string& from, const string& to, int weight) = 0;
virtual int findShortestPath(const string& start, const string& end) = 0;
virtual vector<string> getVertices() = 0;
};
  1. 定义适配器
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
class GraphAdapter : public Graph {
private:
LegacyGraph legacyGraph;
unordered_map<string, int> vertexMap;
vector<string> vertices;

public:
GraphAdapter(int size) : legacyGraph(size) {
vertexMap.reserve(size);
}

void addEdge(const string& from, const string& to, int weight) override {
auto fromIt = vertexMap.find(from);
auto toIt = vertexMap.find(to);
if (fromIt != vertexMap.end() && toIt != vertexMap.end()) {
legacyGraph.addEdge(fromIt->second, toIt->second, weight);
}
}

void addVertex(const string& name) {
vertexMap[name] = vertexMap.size();
vertices.push_back(name);
}

int findShortestPath(const string& start, const string& end) override {
auto startIt = vertexMap.find(start);
auto endIt = vertexMap.find(end);
if (startIt != vertexMap.end() && endIt != vertexMap.end()) {
return legacyGraph.computeShortestPath(startIt->second, endIt->second);
}
return -1;
}

vector<string> getVertices() override {
return vertices;
}
};
  1. 创建适配器
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// 创建适配器
GraphAdapter graphAdapter(4); // 假设顶点数为4
graphAdapter.addVertex("A");
graphAdapter.addVertex("B");
graphAdapter.addVertex("C");
graphAdapter.addVertex("D");

// 添加边
graphAdapter.addEdge("A", "B", 10);
graphAdapter.addEdge("B", "C", 20);
graphAdapter.addEdge("C", "D", 30);
graphAdapter.addEdge("A", "D", 100);

// 计算最短路径
int distance = graphAdapter.findShortestPath("A", "D");
cout << "Shortest path from A to D: " << distance << endl;

仅支持多重继承语言,使用较少

Fortran

以下代码只尽量确保与 CPP 形式一致,不一定是最佳实践

对象适配器模式

  1. 被适配者
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
module legacy_graph_module
implicit none
private

type, public :: LegacyGraph
private
integer, dimension(:, :), allocatable :: adjacency_matrix ! 邻接矩阵
integer :: num_vertices ! 顶点数
contains
procedure :: ptr_add_edge => add_edge
procedure :: ptr_compute_shortest_path => compute_shortest_path
final :: deallocate_graph
end type LegacyGraph

interface LegacyGraph
module procedure :: legacy_graph_constructor
end interface LegacyGraph

contains

function legacy_graph_constructor(vertices) result(graph)
integer, intent(in) :: vertices
type(LegacyGraph) :: graph
end function legacy_graph_constructor

subroutine add_edge(this, src, dest, weight)
class(LegacyGraph), intent(inout) :: this
integer, intent(in) :: src, dest, weight
end subroutine add_edge

integer function compute_shortest_path(this, start, end_node)
class(LegacyGraph), intent(in) :: this
integer, intent(in) :: start, end_node
end function compute_shortest_path

subroutine deallocate_graph(this)
type(LegacyGraph), intent(inout) :: this
end subroutine deallocate_graph

end module legacy_graph_module
  1. 定义目标接口
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
module graph_interface_module
implicit none
private

type, public, abstract :: Graph
contains
procedure(add_edge_proc), deferred :: add_edge
procedure(find_shortest_path_proc), deferred :: find_shortest_path
end type Graph

abstract interface
subroutine add_edge_proc(this, from, to, weight)
import Graph
class(Graph), intent(inout) :: this
character(len=*), intent(in) :: from, to
integer, intent(in) :: weight
end subroutine add_edge_proc

integer function find_shortest_path_proc(this, start, end_node)
import Graph
class(Graph), intent(in) :: this
character(len=*), intent(in) :: start, end_node
end function find_shortest_path_proc
end interface

end module graph_interface_module
  1. 定义适配器
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
module graph_adapter_module
use legacy_graph_module
use graph_interface_module
implicit none
private

type, public, extends(Graph) :: GraphAdapter
private
type(LegacyGraph) :: legacy_graph
integer, dimension(:), allocatable :: vertex_list ! 顶点名称索引
character(len=100), dimension(4) :: vertices ! 存储顶点名称
contains
procedure :: add_vertex
procedure :: add_edge => add_edge_adapter
procedure :: find_shortest_path => find_shortest_path_adapter
end type GraphAdapter

interface GraphAdapter
module procedure :: graph_adapter_constructor
end interface GraphAdapter

contains

function graph_adapter_constructor(vertices) result(graph_)
integer, intent(in) :: vertices
type(GraphAdapter) :: graph_
continue
graph_%legacy_graph = LegacyGraph(vertices)
end function graph_adapter_constructor

subroutine add_vertex(this, name)
class(GraphAdapter), intent(inout) :: this
character(len=*), intent(in) :: name
integer :: i

if (size(this%vertex_list) == 0) then
allocate(this%vertex_list(4))
this%vertex_list = 0
end if

do i = 1, size(this%vertex_list)
if (this%vertex_list(i) == 0) then
this%vertex_list(i) = len_trim(trim(name))
this%vertices(i) = name
exit
end if
end do
end subroutine add_vertex

subroutine add_edge_adapter(this, from, to, weight)
class(GraphAdapter), intent(inout) :: this
character(len=*), intent(in) :: from, to
integer, intent(in) :: weight
integer :: src, dest

src = find_vertex_index(this%vertices, from)
dest = find_vertex_index(this%vertices, to)

if (src > 0 .and. dest > 0) then
call this%legacy_graph%ptr_add_edge(src, dest, weight)
else
print *, "Vertex not found"
end if
end subroutine add_edge_adapter

integer function find_shortest_path_adapter(this, start, end_node)
class(GraphAdapter), intent(in) :: this
character(len=*), intent(in) :: start, end_node
integer :: src, dest

src = find_vertex_index(this%vertices, start)
dest = find_vertex_index(this%vertices, end_node)

if (src > 0 .and. dest > 0) then
find_shortest_path_adapter = this%legacy_graph%ptr_compute_shortest_path(src, dest)
else
find_shortest_path_adapter = -1
end if
end function find_shortest_path_adapter

integer function find_vertex_index(vertices, name)
character(len=*), dimension(:), intent(in) :: vertices
character(len=*), intent(in) :: name
integer :: i

find_vertex_index = -1
do i = 1, size(vertices)
if (vertices(i) == name) then
find_vertex_index = i
exit
end if
end do
end function find_vertex_index

end module graph_adapter_module
  1. 创建适配器
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
program main
use graph_adapter_module
implicit none

type(GraphAdapter) :: graph_adapter
integer :: distance

! 初始化适配器
graph_adapter = GraphAdapter(4)
call graph_adapter%add_vertex("A")
call graph_adapter%add_vertex("B")
call graph_adapter%add_vertex("C")
call graph_adapter%add_vertex("D")

! 添加边
call graph_adapter%add_edge("A", "B", 10)
call graph_adapter%add_edge("B", "C", 20)
call graph_adapter%add_edge("C", "D", 30)
call graph_adapter%add_edge("A", "D", 100)

! 计算最短路径
distance = graph_adapter%find_shortest_path("A", "D")
print *, "Shortest path from A to D:", distance

end program main

Reference

shusheng007 | 秒懂设计模式之适配器模式(Adapter Pattern)

0%