设计模式之工厂方法模式

简单工厂模式提供了专门的工厂类用于创建对象,实现了对象的创建和使用分离。但工厂类集中了所有产品对象的创建逻辑,职责过重;此外,如果增加新产品,需要修改工厂类的源代码,违背开闭原则。

工厂方法模式则可以很好的解决这一问题。在工厂方法模式中,不在提供统一的工厂类创建所有的产品对象,而是针对不同的产品提高不同的工厂。

模式结构图如下:

factory-method-pattern

共包含以下 4 个角色:

  • Product:定义产品的接口。也就是产品对象的公共父类。
  • ConcreteProduct:具体产品类,与具体工厂一一对应。
  • Factory:抽象工厂接口。它是工厂方法模式的核心。
  • ConcreteFactory:具体工厂类,返回一个具体产品类的实例。

工厂模式代码:

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
// 抽象产品类
public interface Product {
public void productMethod();
}

// 具体产品类
public class ConcreteProduct implements Product {

@Override
public void productMethod() {
System.out.println("具体产品");
}
}

// 抽象工厂类
public interface Factory {
public Product factoryMethod();
}

// 具体工厂类
public class ConcreteFactory implements Factory {
@Override
public Product factoryMethod() {
// TODO Auto-generated method stub
return new ConcreteProduct();
}
}

// 客户端测试代码
public class Client {

public static void main(String[] args) {
Factory factory;
Product product;
factory = new ConcreteFactory();
product = factory.factoryMethod();
product.productMethod();
}
}

工厂方法模式主要优点:

  • 用户只需要关心所需产品对应的工厂,无需关心创建细节,甚至无需知道具体产品类的类名。
  • 在系统中加入新产品时,无需修改抽象工厂和抽象产品接口,无需修改客户端,也无需修改其他的具体工厂和具体产品,只需要加入一个具体工厂和具体产品就可以。系统的可扩展性非常好。

主要缺点:

  • 添加新产品时,系统中类的个数成对增加,增加了系统的复杂性。同时,抽象层增加了系统的抽象性和理解难度。

Chrome 插件推荐

近些年来,在众多浏览器大战中,Google 的 Chrome 浏览器的市场份额位居首位,而且依然呈现高速增长趋势。Chrome 浏览器的优点不必多言,谁用谁知道。

chrome

这里主要推荐本人常用的 Chrome 插件,能够帮助你更加便捷高效的使用 Chrome 浏览器。

1、Checker Plus for Gmail™

这个插件的强大之处在于你无需打开 Gmail ,即可收到桌面邮件通知,方便地查看、撰写或删除邮件。

checker_plus_for_gmail

2、划词翻译

支持谷歌、百度、有道、必应四大翻译和朗读引擎,可以方便的查看、复制和朗读不同引擎的翻译结果。再也不用担心读不懂英文资料了。

translate

3、OneTab

在 chrome 打开了很多窗口时,内存消耗大,对于配置较低的电脑可能会卡顿,但很多 tab 可能会用到,又不舍得关掉。这个时候你只需要点击 OneTab,就可以直接将所有 tab 回收,稍后重新打开 chrome 都能找到历史记录。

OneTab

4、Markdown Here

对于习惯使用 markdown 的人群来说,markdown 可能是写作的唯一方式。使用 Markdown Here 插件可以让你在 Gmail 中使用 markdown,让你写一封排版漂亮的电子邮件。不仅如此,Markdown Here 还支持 Evernote 和微信公众号。只需要在富文本区域按照 markdown 语法编辑,点击 Markdown Here图标进行转换,或者右键菜单进行 markdown 转换。当然能转换过去也能再转换回来继续编辑。

markdown_here

5、JSONView

通过 Chrome 查看服务器返回的 Json 格式的内容时,基本全是乱的。使用这个插件的好处是它自动排列出 Json 数据,可以很直观的查看数据格式,可谓开发者必备插件。

JSONView

6、Octotree

这个插件能够直接在 Chrome 侧边栏查看 Github 项目文件夹,很方便、很实用。

octotree

7、Save to Pocket

Pocket 是一款稍后读软件,当你在浏览博客或者比较好的文章等,如果当时没有精力消化完,可以用这个插件保存到 Pocket 中,手机上的 Pocket 客户端会实时同步,你可以利用碎片化时间消化保存的知识。而且 Pocket 的阅读排版非常美观大方。pocket

8、印象笔记·剪藏

最后,推荐「印象笔记·剪藏」。如果你使用印象笔记来记录笔记,肯定离不了这个插件,一键保存网页到印象笔记,即时同步到你的手机和电脑,不用复制粘贴编辑再整理。

evernote

这八个是我一直都在使用的插件,推荐给需要的看官。当然啦,Chrome 插件太多了,如果你有觉得不错的插件也可以推荐给我。

朴树《猎户星座》

朴树终于出新专辑了。专辑的名称叫《猎户星座》。4 月 28 号零点在网易云音乐预售数字专辑。

orion

我第一次听到朴树的歌,是在 04 年,电视上播放丰田威驰的广告,放的就是朴树的 「Colorful Days」,当时觉得 MV 里的朴树酷极了。后来高中在学校,每个礼拜二和礼拜四下午放学后,校广播都会放 「Colorful Days」和 「生如夏花」。再后来上大学来到城市,耳边没有消失过的,总是他的歌。

这十多年,朴树一度沉寂,从公众视线中消失。我们这些歌迷一直都在等他,终于有幸看到他归来,热泪盈眶。

今天零点,新专辑第一首,「清白之年」公开,我在零点准时点开,歌曲平缓如徐徐微风,如潺潺流水从指间划走。今天白天再听来,感到一阵无奈哀伤,感叹时间一去不复返。

就如朴树吟唱:

是不是生活太艰难
还是活色生香
我们都遍体鳞伤
也慢慢坏了心肠
你得到你想要的吗
换来的是铁石心肠
可曾还有什么人
再让你幻想

大风吹来了
我们随风飘荡
在风尘中熄灭的清澈目光
我想回头望
把故事从头讲
时光迟暮不返人生已不再来

今天是五一小长假的第一天,哪也没去。一遍又一遍的聆听中。期待明天中午 11 点其他歌曲的公开。

感谢朴树。

设计模式之简单工厂模式

简单工厂模式将有关创建和初始化产品对象的工作搬到一个工厂类中,客户端只需要根据参数调用工厂类的静态方法即可使用工厂类创建的产品对象,无需承担对象的创建工作。这样做的好处就是将对象的创建和使用分离开来,能够防止用来实例化一个类的数据和代码在多个客户端类中到处都是,利于系统维护。

模型结构图如下:

simple_factory_pattern

其中包含以下几个角色:

  • Factory(工厂):负责实现创建所有产品实例的内在逻辑。提供了静态方法便于外界直接调用。
  • Product(抽象产品角色):工厂创建所有产品对象的父类,封装了所有产品对象的公有方法。
  • ConcreteProduct(具体产品角色):每一个具体的产品对象,需要继承抽象产品角色。

具体实现代码:

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
// 抽象产品类
abstract class Product {
// 所有产品类的公共业务方法
public void methodSame() {
// 实现
}

// 声明抽象业务方法
public abstract void methodDiff();
}

// 具体产品类 ProductA
class ProductA extends Product {
@Override
public void methodDiff() {
}
}
// 具体产品类 ProductB
class ProductB extends Product {
@Override
public void methodDiff() {
}
}

// 工厂类
class Factory {
// 静态工厂方法
public static Product createProduct(String arg) {
Product product = null;
if(arg.equalsIgnoreCase("A")) {
product = new ProductA();
} else if(arg.equalsIgnoreCase("B")) {
product = new ProductB();
}
return product;
}
}

// 客户端测试代码
public class Client {

public static void main(String[] args) {
Product product;
product = Factory.createProduct("A"); // 通过工厂类创建产品对象
product.methodSame();
product.methodDiff();
}
}

有时,为了简化工厂模式,可以将抽象产品类和工厂类合并,将静态工厂方法移至抽象产品类。

simple-factory-pattern-2

其主要缺点在于

  • 工厂类集中了所有产品的创建逻辑,一旦不能正常工作,整个系统受到影响。
  • 当引入新的产品,需要修改工厂类的源代码,违反了开闭原则。

适用场景:

  • 产品对象较少,工厂方法的逻辑不会太复杂。

设计模式之单例模式

什么是单例模式?

单例模式是一种对象创建型模式。所谓创建型模式就是将对象的创建和使用分离,在使用对象时无需关心对象的创建细节,从而降低系统的耦合度,使得设计方案更易于修改和扩展。

单例模式三个要点:(1)某个类只能有一个实例。(2)必须自行创建这个实例。(3)必须自行向整个系统提供这个实例。

饿汉式单例类

类加载进来就直接实例化对象,无需考虑多线程安全问题,但是浪费资源严重。

1
2
3
4
5
6
7
8
9
10
public class EagerSingleton {
// 类加载进入内存就创建单一的 instance 对象
private static final EagerSingleton instance = new EagerSingleton();
// 构造函数私有化,禁止外部类直接使用 new 来创建对象
private EagerSingleton() {}
// 提供一个全局的静态方法
public static EagerSingleton getInstance() {
return instance;
}
}

懒汉式单例类

在第一次调用 getInstance() 方法时实例化,类加载时不自行实例化,在需要的时候再加载实例。但在多线程下会出现线程安全问题,可能会创建多个 instance 对象,违背了单例模式的初衷。

1
2
3
4
5
6
7
8
9
10
11
12
13
public class LazySingleton {

private static LazySingleton instance = null;

private LazySingleton() {}

public static LazySingleton getInstance() {
if(instance == null) {
instance = new LazySingleton();
}
return instance;
}
}

为解决多线程问题,可以采用对 getInstance() 方法进行同步,但每次调用getInstance()方法都需要进行线程锁定判断,比较浪费资源,尤其在高并发访问环境下会导致系统性能大大降低。

1
2
3
4
5
6
7
8
9
10
11
12
13
public class LazySingleton {

private static LazySingleton instance = null;

private LazySingleton() {}
// 锁定 getInstance 方法
public static synchronized LazySingleton getInstance() {
if(instance == null) {
instance = new LazySingleton();
}
return instance;
}
}

事实上,无需对整个 getInstance() 方法锁定,只需要锁定代码 “ instance = new LazyInstance() ”。这种方法解决了浪费资源问题,但是在多线程下依然可能出现实例对象不唯一。原因在于:假如某一瞬间线程 A 和线程 B 都在调用getInstance() 方法,此时 instance 对象为 null,均能通过 “ instance == null ” 的判断。线程 A 进入 synchronized 锁定的代码中执行实例创建代码,线程 B 处于排队等待状态。当 A 执行完毕创建了实例后,线程 B 进入 synchronized 代码,此时 B 并不知道实例已经创建,将创建新的实例。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public class LazySingleton {

private static LazySingleton instance = null;

private LazySingleton() {}

public static synchronized LazySingleton getInstance() {
if(instance == null) {
syncronized(LazySingleton.class) {
instance = new LazySingleton();
}
}
return instance;
}
}

因此还得进行改进,在 synchronized 锁定代码中再进行一次 “ instance == null ” 判断,这种方式称为双重检查锁定 。需要注意的是在需要在静态成员变量前加 volatile 修饰符。但 volatile 关键字会屏蔽 Java 虚拟机做的一些代码优化,导致系统运行效率降低。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public class LazySingleton {

private volatile static LazySingleton instance = null;

private LazySingleton() {}

public static LazySingleton getInstance() {
// 第一重判断
if(instance == null) {
// 锁定代码块
syncronized(LazySingleton.class) {
// 第二重判断
if(instance == null) {
instance = new LazySingleton();
}
}
}
return instance;
}
}

IoDH

饿汉式不能实现延迟加载,不管用不用,它始终占据内存;懒汉式 线程控制麻烦,而且性能受到影响。一种被称为 Initialization on Demand Holder(IoDH)的方法能够克服这些缺点。

静态单例对象没有作为 Singleton 的成员变量直接实例化,因此类加载时不会实例化 Singleton,第一次调用 getInstance() 时加载内部类 HolderClass,初始化 instance,由 Java 虚拟机保证其线程安全性,确保其只能初始化一次。

通过使用 IoDH,既可以实现延迟加载,又可以保证线程安全,不影响系统性能。

1
2
3
4
5
6
7
8
9
10
11
12
public class Singleton {

private Singleton() {}

private static class HolderClass {
private final static Singleton instance = new Singleton();
}

public static Singleton getInstance() {
return HolderClass.instance;
}
}

参考资料

<设计模式的艺术之道> 刘伟

博客配置更新

今天,将博客主题由 next 换成了 scribble,关于博客的安装和 next 主题的配置详见 GitHub Pages + Hexo 搭建博客。 然后对博客添加了些许功能。

添加网易云跟帖

由于多说评论即将停用,所以添加了网易云跟帖作为博客的评论系统。

首先登录网易云跟帖,然后进入后台管理,填写站点信息,站点网址处需填自己申请的域名,填写 github.io 域名会提示站点名称或URL已经存在。

zhandianxinxi

然后点击获取代码,复制通用代码,拷贝至需要放置评论的位置即可。这里要注意本地服务器预览不到效果,部署后,才能看到评论。
huoqudaima

绑定独立域名

购买域名

首先在万网上购买域名,当然也可以去 GoDaddy 购买。

绑定域名与GitHub Pages

首先,修改域名的DNS地址为 f1g1ns1.dnspod.netf1g1ns2.dnspod.net

modifyDNS

然后在本地站点目录里的 source 目录下添加一个 CNAME 文件,不带后缀,文件名要大写。里面添加域名信息(不加 http)。如:wuzhangyang.com 。执行 hexo d -g 部署到 GitHub 上。

注册 DNSPod, 添加域名,添加记录。

addnotes

在记录中,192.30.252.153192.30.252.153 是 Github Pages 服务器指定的 IP 地址。
记录类型为 CNAME,记录值是 zywudev.github.io. 。在记录值中.io后面还有一个小数点。

最后把更改 deploy 到 GitHub 上。

到此,域名绑定好了,在 GitHub 博客仓库的 Settings 里面可以看见以下提示。

dns_success

2017 第一季度

今天是个好日子,与天气无关。

中午正准备午休,忽然收到吉林大学两位专家对毕业论文的盲审评价。

“论文选题与本学科当前发展与经济建设、社会发展有较为密切的联系,有一定的理论意义。运用的理论知识、研究方法和实验手段符合实际情况,理论论证较严密,实验设计较合理,方法和数据较为正确可靠。反映出作者较好地掌握了基础理论和专业知识,反映出作者具有独立从事科研工作的能力。
论文观点正确,条理性好,层次清楚,有逻辑性,文笔较好,文字图表较规范。论文达到了硕士论文水平。同意参加论文答辩。”

“选题有一定的理论意义和比较好的应用价值,有一定的创新性。 创新点明确,对学科相关知识有一定的了解和把握,写作比较规范,内在逻辑比较好,可读性较好。是一个比较完整的研究工作”

虽然知道这其中多为客套话,但心里一块石头终于落下,毕业工作能顺顺利利继续下去了。

今年的第一季度的总结本应前一两个礼拜就写好了,但是受到各种原因(还是拖延症)迟迟未静下心来去写。刚好今天收到了这个好消息,于是,在这绵绵细雨的下午,戴上耳机,把它完成吧。

回望这三个月,主要还是忙毕业论文的事情,花了一个多月把论文初稿写好,一不小心就被抽到盲审了,等到今天才出结果,中间还是挺担心的,毕竟要是盲审没通过影响就大了,还算幸运,顺顺利利。年初说今年要多看书,买了本 「人类简史」, 硬是拖到前几天才看完,拖延症真是不轻啊。这本书确实很值得一读,作者深厚的知识沉淀、惊人的想象力着实让人钦佩,读后受益不浅。后面抽时间写个总结。

这三个月来觉得最为有意义的一件事是加入了 stormzhang 的小密圈,花了 99 元大洋,但感觉非常值得。进圈一个月多以来,从中受益很多,也许是收费的原因,每天都会去上面看看,但主要原因还是圈子里的氛围非常好,过滤掉了一些键盘侠(闲杂人等)。

三个月来回老家一次,也就是前几天的清明节,虽然相隔并不远,但受到交通落后的影响,从上午 8 点多开始,倒腾了好几次车,到下午 3 点多才到家。到家时母亲端出早已准备好了的热腾腾的鸡汤,顿时感觉温暖幸福。其实回家也不只是为了吃好喝好。随着年纪的增长,能明显感觉到父母越来越像自己的朋友,不管大事小事,都愿意跟你分享,他们也希望孩子能跟他们分享。所以现在节假日,我都会选择回家,陪他们聊聊天,其乐融融。

时间总是在不经意间悄悄流去, 17 年已经过去 1/4 了。现在明显感觉到时间不够用,但似乎又感觉自己没什么进步各方面,有些迷茫。但迷茫也许意味着自己在进步吧。临近毕业,调整心态,提高执行力,继续前行。

Android Activity 生命周期

本文目的在于详细总结 Activity 的生命周期。

返回栈

Android 的 Activity 是可以层叠的,以返回栈(Back Stack)存放 Activity。默认情况下,当我们启动一个活动,它会在返回栈中入栈,处于栈顶的位置。当我们按下返回键或者调用 finish() 方法销毁一个活动,处于栈顶的活动会出栈,前一个入栈的活动会重新处于栈顶,用户看到的永远是栈顶的活动。

Activity 四种状态

运行:活动位于返回栈的栈顶,对用户可见。

停止:该活动被另一活动完全遮盖,它对用户不可见,不再处于栈顶。在系统需要内存时可能会被终止。

暂停:当一个活动不再处于栈顶,但此活动仍然可见。也就是说,另一个活动显示在此活动的上方,此活动部分透明或未覆盖整个屏幕。系统仍然会为这种活动保存相应的状态和成员变量,但并不可靠,在内存极低时,仍有可能被系统回收。

销毁:当一个活动从返回栈中被移除。系统最愿意回收这种状态的活动。

Activity 生存期

Activity 类定义了 7 个回调方法。

  • **onCreate()**:首次创建活动时调用,初始化工作,加载布局、绑定事件。后接 onStart()
  • **onStart()**:在活动即将对用户可见之前调用。后接 onResume()
  • **onResume()**:在活动即将开始与用户进行交互之前调用,此时活动位于栈顶。后接 onPause()
  • **onPause()**:当系统即将开始启动或恢复另一个活动时调用。如果活动返回前台,则后接 onResume(),如果活动转入对用户不可见状态,则后接 onStop()
  • **onStop()**:当活动对用户不再可见时调用。如果活动恢复与用户的交互,则后接 onRestart(),如果活动被销毁,则后接 onDestroy()
  • **onDestroy()**:在活动被销毁前调用。
  • **onRestart()**:在活动已停止并即将再次启动前调用。后接 onStart()

整个生存期: 发生在 onCreate()onDestroy() 之间。一般情况,活动会在 onCreate() 中做初始化工作,在 onDestroy() 中释放内存。

可见生存期: 发生在 onStart()onStop() 之间。活动对于用户始终可见,即便不能与用户交互。

前台生存期:发生在 onResume()onPause() 之间。活动始终处于运行状态。

Android 官网提供的 Activity 生命周期图如下图所示。

activity_lifecycle

Demo 实例

1、新建工程 ActivityLifeCycleTest。
2、创建两个子活动 NormalActivity 和 DialogActivity,其中 NormalActivity 是普通的 Activity,DialogActivity 是对话框式的 Activity,在 AndroidManifest.xml 中将 DialogActivity 使用对话框的主题。

1
2
<activity android:name=".DialogActivity"
android:theme="@android:style/Theme.Dialog"></activity>

3、在主活动的布局中添加两个按钮分别用于跳转到两个 Activity。在 MainActivity.java 中重写生命周期图中的七种方法。

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
package com.vincent.activitylifecycletest;
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;

public class MainActivity extends Activity {
public static final String TAG = "MainActivity";

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Log.e(TAG, "onCreate");
setContentView(R.layout.activity_main);
Button startNormalActivity = (Button) findViewById(R.id.start_normal_activity);
Button startDialogActivity = (Button) findViewById(R.id.start_dialog_activity);

startNormalActivity.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Intent intent = new Intent(MainActivity.this, NormalActivity.class);
startActivity(intent);
}
});

startDialogActivity.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Intent intent = new Intent(MainActivity.this, DialogActivity.class);
startActivity(intent);
}
});

}

@Override
protected void onStart() {
super.onStart();
Log.e(TAG, "onStart");
}

@Override
protected void onResume() {
super.onResume();
Log.e(TAG, "onResume");
}

@Override
protected void onPause() {
super.onPause();
Log.e(TAG, "onPause");
}

@Override
protected void onStop() {
super.onStop();
Log.e(TAG, "onStop");
}

@Override
protected void onDestroy() {
super.onDestroy();
Log.e(TAG, "onDestroy");
}

@Override
protected void onRestart() {
super.onRestart();
Log.e(TAG, "onRestart");
}
}

运行工程,主窗口如下左图所示,两个按钮分别用于启动 NormalActivity 和 DialogActivity。
activity_lifecycle_demo

  1. 启动程序首次进入 MainActivity,依次执行了 onCreate() - onStart() - onResume() 方法。
  2. 点击 Start NormalActivity,跳转到 NormalActivity (上图中),依次执行了 onPause() - onStop() 方法。
  3. 按下返回键,依次执行了 onRestart() - onStart() - onResume() 方法。
  4. 点击 Start DialogActivity, 跳出 DialogActivity (上图右),执行了 onPause() 方法。
  5. 按下返回键,执行了 onResume() 方法。
  6. 再按下返回键,依次执行 onPause() - onStop() - onDestroy() 方法。

lifecyclelogcat

参考

Git 命令备忘

对 Git 常用命令归类总结,方便查阅。

Git 配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
git config --global user.name "zywudev" # 全局用户名

git config --global user.email "zywu.dev@gmail.com" # 全局邮箱

git config user.name "zywudev" # 某一个项目使用特地的用户名

git config user.email "zywu.dev@gmail.com" # 某一个项目使用特地的邮箱

git config --global alias.co checkout # 别名

git config --global alias.lg "log --graph --pretty=format:'%Cred%h%Creset -%C(yellow)%
d%Creset %s %Cgreen(%cr) %C(bold blue)<%an>%Creset' --abbrev-commit --date=relative" # 日志

git config --global color.ui true # git 着色

git config --global core.quotepath false # 设置显示中文文件名

Git 常用命令

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
git # 查看 git 是否安装成功

git init # 初始化仓库

git status # 仓库状态

git add <file> # 将文件添加到暂存区

git add . # 将所有修改过的文件添加到暂存区

git rm --cached # 删除缓存,但不删除文件

git rm <file> # 删除文件

git commit -m “first commit” # 提交

git log # 可以查看所有产生的 commit 记录

git tag v1.0 # 给当前代码打标签

git tag # 查看历史 tag 记录

git checkout v1.0 # 切换到 v1.0 的代码状态

git diff <$id1> <$id2> # 比较两次提交之间的差异

git diff <branch1>..<branch2> # 在两个分支之间比较

git diff --staged # 比较暂存区和版本库差异

git checkout -<file> # 抛弃工作区修改

git checkout . # 抛弃工作区修改

git stash # 当前分支暂存

git stash list # 列所有stash

git stash apply # 恢复暂存的内容

git stash drop # 删除暂存区(删除一条)

git stash clear # 清空暂存区

分支管理

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
git branch # 查看分支情况

git branch a # 新建 a 分支

git checkout a # 切换到 a 分支

git checkout -b a # 新建 a 分支 自动切换到 a 分支

git merge a # 将 a 分支合并到当前分支

git branch -d a # 删除 a 分支,a 分支已被合并

git branch -D a # 删除 a 分支,a 分支未被合并

git branch -r # 查看远程分支列表

git push origin:<branch> # 删除远程分支

git checkout a origin/a # 本地没有 a 分支的情况下,将远程 a 分支迁到本地

git checkout -b a origin/a # 把远程分支迁到本地顺便切换到该分支:

远程管理

1
2
3
4
5
6
7
8
9
10
11
git push origin master # 把本地代码推到远程 master 分支

git pull origin master # 把远程 master 代码更新到本地

git clone git@github.com:zywudev/weather.git # 远程 test 项目 clone 到本地

git remote add origin git@github.com:zywudev/test.git # 本地已用项目与远程test项目关联,提交到远程test项目

git remote -v # 查看当前项目有哪些远程仓库

git remote show origin # 查看远程服务器仓库状态

GitHub Pages + Hexo 搭建博客

第一篇博客,记录一下博客搭建过程。

安装 node.js

node.js

安装 Git

Git

安装 Hexo

在文件夹中建立名为 hexo 的文件夹,右键打开 Git Bush,使用 npm 安装 Hexo。

1
npm install hexo-cli -g

初始化 blog, Hexo 自动在 blog 文件夹下创建网站所需文件。

1
hexo init blog

进入 blog 文件夹,安装依赖包。

1
2
cd blog
npm install

生成静态页面

1
hexo g # 或 hexo generate 

启动本地 web 服务

1
hexo s # 或 hexo server

此时在浏览器地址栏中键入 http://localhost:4000/ , 可以看到内置的页面。

hexo-init-page

GitHub Pages 设置

注册 GitHub 及其使用可以参考 从 0 开始学习 GITHUB 系列汇总

在 GitHub 上创建仓库,而且仓库的名字格式为: username.github.io,username 与 GitHub 账号名对应,每个帐号只能有一个仓库来存放个人主页。可以通过 http://username.github.io 来访问个人主页。

部署 Hexo 到 GitHub Pages

其实就是将 Hexo 生成的静态页面提交 (git commit) 到 GitHub 上。

在 Hexo 根目录下的配置文件 _config.yml 中进行修改:

1
2
3
4
deploy:
type: git
repo: git@github.com:zywudev/zywudev.github.io.git
branch: master

还得安装一个扩展

1
npm install hexo-deployer-git --save

然后在命令行部署

1
hexo d

Hexo 主题基本配置

选择喜欢的主题。Hexo 官网主题。我的博客选用的是 NexT 主题,官方提供了详细的使用文档

下载 NexT 主题

1
git clone https://github.com/iissnan/hexo-theme-next themes/next

启用 NexT 主题

克隆完成后,打开站点配置文件 __config.yml,找到 theme 字段,修改为:

1
theme: next

站点配置文件:博客目录下的 __config.yml 文件。

主题配置文件: themes/next 目录下的 __config.yml 文件。

启动本地 web 服务验证

1
hexo s --debug

至此,即完成了基于 GitHub Pages + Hexo 的个人博客框架搭建。

博客推广

将个人博客推广到 Google 搜索引擎上。

验证网站

推荐文件验证。

下载 HTML 验证文件,将该文件放到博客 source 目录下。

hexo 编译文件时,会给下载的 HTML 文件中添加其他的内容,导致验证失败,所以需要在文件开头添加 layout: false 来取消 hexo 对其进行的转换。

1
2
layout: false   ---
google-site-verification: googleb6fc53a32f5418d9.html

部署到 GitHub,输入https://zywudev.github.io/googleb6fc53a32f5418d9.html , 能访问即可点击验证按钮进行验证。

站点地图

站点地图是一种文件,您可以通过该文件列出您网站上的网页,从而将您网站内容的组织架构告知 Google 和其他搜索引擎。Google 等搜索引擎网页抓取工具会读取此文件,以便更加智能地抓取您的网站。

使用 hexo-generator-sitemap 插件来生成 Sitemap,执行

1
npm install hexo-generator-sitemap --save

执行

1
hexo g

博客根目录的public下面生成了 sitemap.xml 。如果没有,在博客目录的 _config.yml 中添加如下代码重新编译

1
2
sitemap:
path: sitemap.xml

要将博客目录 __config.yml 中的 url 字段设置为自己的域名

1
url: http://zywudev.github.io

部署到 Github,访问 https://zywudev.github.io/sitemap.xml

提交 sitemap 到 Google站长工具,找到添加站点地图按钮,添加 sitemap.xml 即可,如下图。

google-sitemap

博客优化

添加 about 页面

1
hexo new page "about" 

\source\about\ 目录下会生成一个 index.md 文件,添加个人信息即可。

添加分类、标签页面

1
2
hexo new page "categories"
hexo new page "tags"

博客标题、作者等

打开站点配置文件

1
2
3
4
5
6
title: Wu's blog 
subtitle:
description: O ever youthful,O ever weeping
author: Wu
language: zh-Hans
timezone:

修改文章内文本链接样式

将文本链接设置为蓝色,修改
themes\next\source\css\_common\components\post\post.styl,
添加

1
2
3
4
5
6
7
8
9
.post-body p a{
color: #0593d3;
border-bottom: none;

&:hover {
color: #0477ab;
text-decoration: underline;
}
}

通过网站 favicon在线制作 网站制作 favicon 图片。

将图片放在博客 source 目录下即可。

添加 Fork me on GitHub 挂件

官网选取样式。

拷贝代码,修改 href 地址为自己的 GitHub 地址

1
2
3
<a href="https://github.com/you">
改为:
<a href="https://github.com/zywudev">

修改文件: themes/next/layout/_layout.swig,将代码拷贝至对应位置。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<body>

{% include '_scripts/third-party/analytics.swig' %}

<div class="{{ container_class }} {% block page_class %}{% endblock %} ">
<div class="headband"></div>

<!--------------add Fork me on GitHub ------------->

<a href="https://github.com/zywudev"><img style="position: absolute; top: 0; left: 0; border: 0;" src="https://camo.githubusercontent.com/8b6b8ccc6da3aa5722903da7b58eb5ab1081adee/68747470733a2f2f73332e616d617a6f6e6177732e636f6d2f6769746875622f726962626f6e732f666f726b6d655f6c6566745f6f72616e67655f6666373630302e706e67" alt="Fork me on GitHub" data-canonical-src="https://s3.amazonaws.com/github/ribbons/forkme_left_orange_ff7600.png"></a>

<!--------------add Fork me on GitHub ------------->

<header id="header" class="header" itemscope itemtype="http://schema.org/WPHeader">
<div class="header-inner"> {%- include '_partials/header.swig' %} </div>
</header>

参考链接

如何搭建一个独立博客——简明Github Pages与Hexo教程

手把手教你使用Hexo + Github Pages搭建个人独立博客

博客推广——提交搜索引擎