-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy path20190509.html
340 lines (294 loc) · 23.8 KB
/
20190509.html
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
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
<html >
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no, minimal-ui">
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vue.js"></script>
<script async src="https://busuanzi.ibruce.info/busuanzi/2.3/busuanzi.pure.mini.js"></script>
<link href="https://cdn.bootcdn.net/ajax/libs/vuetify/2.6.12/vuetify.min.css" rel="stylesheet">
<script src="https://cdn.bootcdn.net/ajax/libs/vuetify/2.0.4/vuetify.min.js"></script>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/highlightjs/[email protected]/build/styles/rainbow.min.css">
<script src="https://cdn.jsdelivr.net/gh/highlightjs/[email protected]/build/highlight.min.js"></script>
<link href="https://cdn.bootcdn.net/ajax/libs/MaterialDesign-Webfont/6.9.96/css/materialdesignicons.min.css" rel="stylesheet">
<link href="/css/three-cards-style.css" rel="stylesheet">
<meta name="robots" contect= "all">
<meta name="description" contect="一个热爱学习的 Java 程序员,喜欢 Vue,喜欢深度学习">
<!-- 主页使用 category作为 keywords,文章页使用文章的 keywords -->
<meta name="keywords" contect="java,Design Pattern,设计模式,六大设计原则">
<link rel="icon shortcut" type="image/ico" href=/images/favicon.jpg>
<title>
U2647's blog
</title>
<!-- 百度统计 -->
<!-- Google Search Console -->
<meta name="generator" content="Hexo 6.3.0"></head>
<body>
<div id="app">
<v-app>
<!-- 页头 -->
<v-card tile elevation="24" style="width: 80%; margin: 0 auto; text-align:center; background:rgba(0,0,0,0); margin-bottom: 3%;" gradient="to bottom, rgba(0,0,0,.1), rgba(0,0,0,.5)">
<v-img height="240" src="" class="white--text align-end" >
<v-card-title style="text-align: left; margin-left: 0.3%;">U2647's blog</v-card-title>
<v-card-text style="text-align: left;margin-left: 0.3%;" class="white--text">
一个热爱学习的 Java 程序员,喜欢 Vue,喜欢深度学习
</v-card-text>
<v-divider style="margin-left: 1.3%; margin-right: 1.3%;" class="success lighten-1"></v-divider>
<v-card-text style="text-align: left;" class="white--text">
<v-btn text class="white--text" style="text-transform:capitalize;" href="/categories/Dubbo">Dubbo</v-btn>
<v-btn text class="white--text" style="text-transform:capitalize;" href="/categories/Flutter">Flutter</v-btn>
<v-btn text class="white--text" style="text-transform:capitalize;" href="/categories/SpringBoot">SpringBoot</v-btn>
<v-btn text class="white--text" style="text-transform:capitalize;" href="/categories/Debug">Debug</v-btn>
<v-btn text class="white--text" style="text-transform:capitalize;" href="/categories/Notes">Notes</v-btn>
<v-btn text class="white--text" style="text-transform:capitalize;" href="/categories/Java">Java</v-btn>
<v-btn text class="white--text" style="text-transform:capitalize;" href="/categories/LeetCode">LeetCode</v-btn>
<v-btn text class="white--text" style="text-transform:capitalize;" href="/categories/Python">Python</v-btn>
<v-btn text class="white--text" style="text-transform:capitalize;" href="/categories/Redis">Redis</v-btn>
<v-btn text class="white--text" style="text-transform:capitalize;" href="/categories/Android">Android</v-btn>
<v-btn text class="white--text" style="text-transform:capitalize;" href="/categories/DesignPattern">DesignPattern</v-btn>
</v-card-text>
</v-img>
<v-divider style="margin-left: 1.3%; margin-right: 1.3%;" class="success lighten-1"></v-divider>
<v-card-actions >
<v-btn text x-large class="white--text" style="margin-left: 0.5%;margin-top:0.5%;margin-bottom: 0.5%;" href=/>
<v-icon right>
mdi-home-outline
</v-icon>
首页
</v-btn>
<v-btn text x-large class="white--text" style="margin-left: 0.5%;margin-top:0.5%;margin-bottom: 0.5%;" href=/tags>
<v-icon right>
mdi-cloud-outline
</v-icon>
标签云
</v-btn>
<v-btn text x-large class="white--text" style="margin-left: 0.5%;margin-top:0.5%;margin-bottom: 0.5%;" href=/timeline>
<v-icon right>
mdi-timeline-text-outline
</v-icon>
时间轴
</v-btn>
<v-spacer></v-spacer>
<v-btn text x-large class="white--text" style="margin-left: 0.5%;margin-top:0.5%;margin-bottom: 0.5%;">
<v-icon right>
mdi-draw-pen
</v-icon>
文章总数
</v-btn >
<v-btn icon style="margin-right: 0.5%;margin-top:0.5%;margin-bottom: 0.5%;">
<v-avatar color="success" size="35" >
<span class="white--text"> 62 </span>
</v-avatar>
</v-btn>
</v-card-actions>
</v-card>
<div style="width: 55%; margin: 0 auto; text-align:center;">
<v-card tile max-width="100%" elevation="24" style="margin-bottom: 3%;" >
<v-img height="240" class="white--text align-end" src=/random/material-22.jpg gradient="to bottom, rgba(0,0,0,.1), rgba(0,0,0,.5)">
<v-card-title style="text-align: left;margin-left: 0.6%;">
<span>设计模式-六大设计原则</span>
</v-card-title>
<v-card-text style="text-align: left;margin-left: 0.8%;">
设计模式-六大设计原则
</v-card-text>
<v-divider class="success lighten-1" style="margin-left:2%; margin-right: 2%;"></v-divider>
<v-card-actions style="text-align: left;" class="white--text" style="margin-left:2%; margin-right: 2%;">
<v-btn text class="white--text" style="text-transform:capitalize;margin-left:0.5%;">Design Pattern</v-btn>
<v-btn text class="white--text" style="text-transform:capitalize;margin-left:0.5%;">设计模式</v-btn>
<v-btn text class="white--text" style="text-transform:capitalize;margin-left:0.5%;">六大设计原则</v-btn>
<v-spacer></v-spacer>
<v-btn text class="white--text" >
<v-icon right>
mdi-cursor-default-click-outline
</v-icon>
点击量
</v-btn >
<v-btn icon >
<v-avatar color="success" size="35" >
<span id = "busuanzi_value_page_pv" class="white--text"> 62 </span>
</v-avatar>
</v-btn>
</v-card-actions>
</v-img>
<v-card-text>
<div id = "post_container" class="text-justify" style="padding-left: 2%;padding-right: 2%;padding-bottom: 2%">
<p><strong>注意:阅读本文时,强烈建议先阅读下 OneMall 项目的概要设计</strong></p>
<ul>
<li><a target="_blank" rel="noopener" href="https://github.com/zdRan/OneMall">设计模式-OneMall 项目概要设计</a></li>
<li><a href="https://zdran.com/20190509.html">设计模式-六大设计原则</a></li>
<li><a href="https://zdran.com/20190818.html">设计模式-单例模式</a></li>
</ul>
<h2 id="0-前言"><a href="#0-前言" class="headerlink" title="0. 前言"></a>0. 前言</h2><p>谈及设计模式,就不能不提六大设计原则,这六大设计原则就像六颗无限宝石一样强大。所有的设计模式都是为了尽量的实现某个或者某些设计原则。</p>
<p>通俗一点,设计原则是接口,而设计模式就是具体的实现类。所以我们先看一下这个接口里到底有哪些方法。</p>
<h2 id="1-单一职责原则-SRP:Single-responsibility-principle"><a href="#1-单一职责原则-SRP:Single-responsibility-principle" class="headerlink" title="1. 单一职责原则(SRP:Single responsibility principle)"></a>1. 单一职责原则(SRP:Single responsibility principle)</h2><p>以我们的 OneMall 商城为例。商城首先得有用户吧,用户要有用户名、密码、余额,这些信息,而且也要有修改用户名、密码、充值、支付这些操作吧。我们看一下用户这个类的设计。</p>
<p><img src="https://tva1.sinaimg.cn/large/008eGmZEly1gmpx34udwoj30qp0ifmxm.jpg" alt="2_1_userInfo类图"></p>
<p>我相信稍微懂点设计的人都能看出这个类的设计有问题,因为把用户的属性和用户的行为放到了个类里面。应该把用户的属性和用户的行为分开,重新设计一下这个类。</p>
<p><img src="https://tva1.sinaimg.cn/large/008eGmZEly1gmpx3byrrmj30rs0jhdgb.jpg" alt="2_2_userInfo类图"></p>
<p>上面这种把一个类拆分成了两个类就是遵循了 <strong>单一职责原则</strong> 。</p>
<p>单一职责原则的定义是:</p>
<p><strong>SRP:There should never be more than one reason for a class to change</strong></p>
<p><strong>引起一个类的变化原因绝对不能超过一个</strong></p>
<p>就像上面的例子一样,修改用户属性会引起类的变化,处理业务逻辑(充值、支付)也会引起类的变化,依据单一职责原则,所以我们把类拆成了两个。</p>
<p>我们在设计类或者是接口的时候尽量做到职责单一,这样才能使每个类的职责更加清晰。</p>
<h2 id="2-里式替换原则-Liskov-Substitution-Principle-LSP"><a href="#2-里式替换原则-Liskov-Substitution-Principle-LSP" class="headerlink" title="2. 里式替换原则(Liskov Substitution Principle LSP)"></a>2. 里式替换原则(Liskov Substitution Principle LSP)</h2><p>因为我们对接了不同的商城,每个商城,都有每个商城自己的下单逻辑,但是我们对外提供的下单逻辑只能有一套,所以需要封装一下,这里就遵守出了 <strong>里式替换原则</strong>。</p>
<p>在一般的 MVC 架构中,我们一般有 Controller、Service层。而 Service 层一般是接口和对应的实现类,类图如下</p>
<p><img src="https://tva1.sinaimg.cn/large/008eGmZEly1gmpx3kpudpj30rn0kxjrm.jpg" alt="2_3_order类图"></p>
<p>我们在下单的时候可以使用接口中的 submitOrder,具体的实现逻辑放在不同的子类里,比如我们可以有 JDSubmitOrderServiceImpl、 TMSubmitOrderServiceImpl 等。</p>
<p>里式替换原则:</p>
<pre><code>If for each object o1 of type S there is an object o2 of type T such that for
all programs P defined in terms of T,the behavior of P is unchanged when o1
is substituted for o2 then S is a subtype of T.
如果对每一个类型为S的对象o1,都有类型为T的对象o2,
使得以T定义的所有程序P在所有的对象o1都代换成o2时,程序P的行为没有发生变化,
那么类型S是类型T的子类型。
</code></pre>
<p>这是一种标准定义。还有一种通俗的定义:</p>
<pre><code>Functions that use pointers or references to base classes must be able to
useobjects of derived classes without knowing it.
所有引用基类的地方必须能透明地使用其子类的对象。
</code></pre>
<p>再换句话说,就是 <strong>任何基类可以出现的地方,子类一定可以出现</strong>。</p>
<p>里式替换原则是在告诉我们,继承关系应该遵循哪些原则? 或者说,如果你要使用继承,那么你就应该遵守里式替换原则。</p>
<p>里氏替换原则主要阐述了有关继承的一些原则,也就是什么时候应该使用继承,什么时候不应该使用继承,以及其中蕴含的原理。里氏替换原则是继承复用的基础,它反映了基类与子类之间的关系,是对开闭原则的补充,是对实现抽象化的具体步骤的规范。</p>
<p>里式替换原则有四层含义,或者说,当你实现继承的时候,应该遵守这四个规则。</p>
<ul>
<li>子类必须完全实现父类的方法</li>
</ul>
<p>如果子类不能够完全实现父类的方法,那么建议断绝继承关系,使用组合、依赖等代替继承关系。</p>
<p>比如我们的例子中,如果有一个类 XXXOrderServiceImpl 继承了 SubmitOrderService,但是没有实现 Service 中的接口,那么就应该断绝继承关系。</p>
<p>PS:其实这个原则应该没有说完,还有下句。<strong>子类必须完全实现父类的方法。但不得重写(覆盖)父类的非抽象(已实现)方法</strong></p>
<p>就是说子类不能改变父类已经实现好的方法,不能改变父类方法的逻辑。</p>
<ul>
<li>子类可以有自己的个性</li>
</ul>
<p>或者说,子类可以有自己独有的方法、属性。但是这里需要注意:如果你在子类中定义了方法,那么你在使用这个类的时候就不能使用多肽了。</p>
<p>子类不仅可以继承父类中的方法和属性,还可以定义自己的方法和属性。但是这样做之后,就不能使用多肽了,比如,当我们在使用下单逻辑的时候,一般会这么定义:</p>
<pre><code>SubmitOrderService orderService = new JDSubmitOrderServiceImpl();
orderService.submitOrder();
</code></pre>
<p>但是,如果我们在 JDSubmitOrderServiceImpl 中定义了一个自己的方法 xxxOrder(),如果想要使用该方法,就不能使用上面这种定义方式。</p>
<pre><code>JDSubmitOrderServiceImpl orderService = new JDSubmitOrderServiceImpl();
orderService.xxxOrder();
</code></pre>
<p>只能使用 JDSubmitOrderServiceImpl 作为对象的类型。</p>
<ul>
<li>覆盖或实现父类的方法时输入参数(方法的参数)可以被放大</li>
</ul>
<p>比如,我们在实现 SubmitOrderService 的时候,重写 submitOrder 方法的时候,可以将方法的参数定义成 Order 或者是 Order 的父类。 </p>
<p>比如我们 SubmitOrderService 有个方法<code>xxxOrder(ArrayList list)</code> 参数是一个 <code>ArrayList</code>,在实现这个方法的时候可以传入 ArrayList 的父类,可以这么定义<code>xxxOrder(List list)</code></p>
<p>PS: 这里说的是参数可以被放大,是当你有不得不放大参数的时候,可以放大,而不是只要实现就去放大参数,一般在实现的时候尽量不要放大,而且,一般父类的方法参数都是某个类的父类,很少使用子类的,所以很少遇到放大参数的情况。</p>
<p>注意: 这里说的是方法定义的时候可以被放大。在实际调用的时候可以传入一个参数的子类。比如:</p>
<pre><code>SubmitOrderService orderService = new JDSubmitOrderServiceImpl();
orderService.submitOrder(new JDOrder());
</code></pre>
<p>这里我们传入的参数是 Order 的子类。而不是父类。</p>
<ul>
<li>覆写或实现父类的方法时输出结果(方法的返回值)可以被缩小</li>
</ul>
<p>跟第 3 条对应,这里说的是方法的返回值可以被缩小,比如父类方法的返回值是 List ,那么子类的返回值可以是 List 或者是 List 的子类。比如 ArrayList。</p>
<h2 id="3-依赖倒置原则-Dependence-Inversion-Principle-DIP"><a href="#3-依赖倒置原则-Dependence-Inversion-Principle-DIP" class="headerlink" title="3. 依赖倒置原则(Dependence Inversion Principle DIP)"></a>3. 依赖倒置原则(Dependence Inversion Principle DIP)</h2><p>还是以上面的 Order 类图为例,我们在定义 SubmitOrderService 的方法的时候依赖了 Order 类,在设计的时候我们使用的是 Order 类,而不是 JDOrder 这个子类,这里的设计就遵守了 <strong>依赖倒置原则</strong>。</p>
<p>依赖倒置原则的定义:</p>
<pre><code>High level modules should not depend upon low level modules,Both should depend
upon abstractions.
高层模块不应该依赖低层模块,两者都应该依赖抽象
Abstractions should not depend upon details.
抽象不应该依赖细节
Details should depend upon abstracts.
细节应该依赖抽象
</code></pre>
<p>高层模块一般是抽象层,低层模块是具体的实现层,在上面的例子中 SubmitOrderService 就是高层模块,JDSubmitOrderServiceImpl、 JDOrder 就是低层模块。</p>
<p>在这个例子中,可以将依赖倒置原则翻译成 SubmitOrderService 不应该依赖 JDOrder, 而应该依赖 JDOrder 的抽象层 Order。 JDSubmitOrderServiceImpl 应该依赖 Order。</p>
<p>这么做是为了方便后期扩展,提高程序的可扩展性,想象一下,我们再增加一个 TMSubmitOrderServiceImpl,如果接口中定义的是 JDOrder,那么我们定义的 TMSubmitOrderServiceImpl 就没办法实现了。 而使用 Order 作为参数,就完全可以正常实现。在调用的时候我们可以传入一个 TMOrder 作为参数。</p>
<p>依赖倒置原则是告诉我们如何设计类的依赖关系,目的是降低类与类之间的耦合,提高系统的稳定性和可扩展性。</p>
<h2 id="4-接口隔离原则-Interface-Segregation-Principle-ISP"><a href="#4-接口隔离原则-Interface-Segregation-Principle-ISP" class="headerlink" title="4. 接口隔离原则(Interface Segregation Principle ISP)"></a>4. 接口隔离原则(Interface Segregation Principle ISP)</h2><p>假如我们需要设计一个订单相关的接口, OrderService 这个服务可能会提供一些增删改查的接口,提供给管理模块使用,还有一些订单相关的接口,比如下单接口,订单撤销接口,这些接口不应该放到 OrderService 中。而是写在另外一个 Service 中,比如我们上文中的 SubmitOrderService 中。这里就遵守了 <strong>接口隔离原则</strong></p>
<p><img src="https://tva1.sinaimg.cn/large/008eGmZEly1gmpx3zbcijj30rl0jzglz.jpg" alt="2_4_order类图"></p>
<p>OrderManager 不应该依赖下单,相关的接口,所以需要将下单相关的接口”隔离”出来。</p>
<p>接口隔离原则有两种定义:</p>
<ul>
<li><p>Clients should not be forced to depend upon interfaces that they don’t use.(客户端不应该依赖它不需要的接口。)</p>
</li>
<li><p>The dependency of one class to another one should depend on the smallest possible interface.(类间的依赖关系应该建立在最小的接口上。)</p>
</li>
</ul>
<p>针对我们上面的例子</p>
<ul>
<li>客户端(OrderManager) 不应该依赖它不需要的接口(下单接口)。</li>
<li>OrderManager 与 OrderService 的依赖关系应该建立在最小的接口上。</li>
</ul>
<p>接口隔离原则是在告诉我们,应该以什么规则将接口组合到一起,应该以什么规则将接口拆分到不同的类中。</p>
<p>PS: 接口隔离原则中的”接口”,是指的 Java 中 interface 里某个具体的方法。而不是 Java 中使用 interface 声明的某个 class 文件</p>
<h2 id="5-迪米特法则-Least-Knowledge-Principle-LKP"><a href="#5-迪米特法则-Least-Knowledge-Principle-LKP" class="headerlink" title="5. 迪米特法则(Least Knowledge Principle LKP)"></a>5. 迪米特法则(Least Knowledge Principle LKP)</h2><p>以商城为例,假如我们的分销商城 AMall 需要获取一个商品信息,一种做法是,我们提供 2 个接口,JDGoodsService 用于提供 JD 商城的商品信息,一个 TMGoodsService 用于提供 TM 商城的商品信息,AMall 分别调用不同的接口获取商品信息。 </p>
<p>上面这种设计就违反了 <strong>迪米特法则</strong>, 注意,是 <strong>违反</strong> 了迪米特法则。</p>
<p>迪米特法则又叫最小知识原则,标准的定义是:</p>
<p>Only talk to your immediate friends(只与直接的朋友通信)</p>
<p>根据我们上面的这个例子,AMall 需要获取商品信息,不应该直接与 JD、TM 等接口通信,而是 OneMall 提供统一的接口,用于获取商品信息,至于具体是获取 JD 的商品还是 TM 的商品,那应该是 OneMall 该操心的事情,上面的例子中我们的 AMall 跨过了 OneMall 直接与具体的商城接口通信,就是违反了迪米特法则。</p>
<p>迪米特法则是在告诉我们如何处理接口与接口之间的依赖关系。遵守迪米特法则,可以让代码更加容易扩展,比如,将来我们增加一个 TB 的商城接口,对 AMall 来说是不需要做修改的。</p>
<h2 id="6-开闭原则-Open-Close-Principle-OCP"><a href="#6-开闭原则-Open-Close-Principle-OCP" class="headerlink" title="6. 开闭原则(Open Close Principle OCP)"></a>6. 开闭原则(Open Close Principle OCP)</h2><p>还是以我们的 OneMall 商城为例,现在我对接了 JD 商城、TM 商城、TB 商城、如果我们后期要对接其他的商城,我们的 OneMall 商城应该通过扩展(增加)类接口的方式来实现功能,而不是通过修改接口和类来实现。</p>
<p>如果能够通过扩展来实现,说明我们的项目设计就是遵守了 <strong>开闭原则</strong>。</p>
<p>开闭原则的定义:</p>
<p>Software entities like classes,modules and functions should be open for extension but closed for<br>modifications.(一个软件实体如类、模块和函数应该对扩展开放,对修改关闭。)</p>
<p>代码设计如果遵守了开闭原则,可以使代码更容易扩展。</p>
<p>开闭原则是之前五大设计原则的更高层的抽象,或者说,之前的五大设计原则是开闭原则的具体体现。</p>
<p>可能有点绕,可以这么理解,我们在设计代码的时候,终极目标就是希望代码符合或者遵守开闭原则,而具体应该怎么设计才能够符合开闭原则呢,就是尽量遵守其他五大设计原则!</p>
<h2 id="7-总结"><a href="#7-总结" class="headerlink" title="7. 总结"></a>7. 总结</h2><ul>
<li>Single Responsibility Principle:单一职责原则</li>
<li>Open Closed Principle:开闭原则</li>
<li>Liskov Substitution Principle:里氏替换原则</li>
<li>Law of Demeter:迪米特法则</li>
<li>Interface Segregation Principle:接口隔离原则</li>
<li>Dependence Inversion Principle:依赖倒置原则</li>
</ul>
<p>将这六个原则的首字母组合起来就是 SOLID(solid 稳定的),代表的含义是这六个原则组合使用起来可以建立稳定的、灵活的、可靠地项目。</p>
</div>
</v-card-text>
<v-divider class="success lighten-1" ></v-divider>
<v-card-text>
<v-alert style="margin-left:2%; margin-right: 2%;padding-top: 2%;padding-bottom: 2%;" dense text border="left" type="success">
版权声明:本博客所有文章除特别声明外,均采用 <a href="/creativecommons.html" target="_blank">CC BY-NC-SA 4.0 </a>许可协议。转载请注明出处!
</v-alert>
</v-card-text>
</v-card>
<!-- 分页 -->
</div>
<!-- 页脚 -->
<div style="width: 100%; margin-top: 2%; text-align:center;">
<v-footer padless style="background:rgba(76,175,80,0.4);">
<v-card style="width: 100%; text-align:center;background:rgba(0,0,0,0);" gradient="to top, rgba(0,0,0,.2), rgba(0,0,0,.8)" tile elevation="24" class="white--text text-center">
<v-card-actions style="text-align: center;">
<v-chip class="white--text" style="background:rgba(0,0,0,0);" href=https://github.com/zdRan>
我的GitHub
</v-chip>
<v-chip class="white--text" style="background:rgba(0,0,0,0);" href=https://leetcode.cn/u/u2647>
我的LeetCode
</v-chip>
<v-chip class="white--text" style="background:rgba(0,0,0,0);" href=https://juejin.cn/user/3896324938793943>
我的掘金
</v-chip>
<v-spacer></v-spacer>
<div>
<v-list-item two-line>
<!-- 很高兴您使用本主题,开发不易,希望您保留一下版权声明,它并不会影响页面效果 ~ -->
<v-list-item-content style="text-align: left;display: inline-block;">
<v-list-item-subtitle class="white--text">Powered by <a target="_blank" rel="noopener" href="https://hexo.io/zh-cn/" style="color: white;"><strong>Hexo</strong></a></v-list-item-subtitle>
<v-list-item-subtitle class="white--text">Powered by <a target="_blank" rel="noopener" href="https://github.com/zdRan/three-cards" style="color: white;"><strong>three-cards</strong></a></v-list-item-subtitle>
</v-list-item-content>
</v-list-item>
</div>
</v-card-actions>
<v-divider class="success lighten-1"></v-divider>
<v-card-text class="white--text">
Copyright © 2017 - {{ new Date().getFullYear() }} <a target="_blank" href="http://www.miitbeian.gov.cn" rel="nofollow noopener" style="color: white;">某ICP备xxxxxxxx号</a>
</v-card-text>
</v-card>
</v-footer>
</div>
</v-app>
</div>
<script>
new Vue({
el: '#app',
vuetify: new Vuetify(),
});
//加载代码高亮
hljs.highlightAll();
</script>
</body>
</html>