考虑使用构建器(二)

考虑使用构建器

这个比较好理解,能够解决多参数构造器的复杂性,相对于get和set的JavaBean来说也有线程安全性的优势,个人倾向于使用lombok的@Builder注解,注解虽好用,不过也需要了解下注解背后的一些原理。

先看一下我写的一个简单示例

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

private String name;

private int age;

public static void main(String[] args) {

Person p = Person.builder().age(15).build();

}
}

再看下官方的标准示例

1
2
3
4
5
6
7
8
9
10
11
//使用lombok注解的
import lombok.Builder;
import java.util.Set;

@Builder
public class BuilderExample {
private String name;
private int age;
@Singular
private Set<String> occupations;
}

等效代码:

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
import java.util.Set;
class BuilderExample {
private String name;
private int age;
private Set<String> occupations;

BuilderExample(String name, int age, Set<String> occupations) {
this.name = name;
this.age = age;
this.occupations = occupations;
}

public static BuilderExampleBuilder builder() {
return new BuilderExampleBuilder();
}

public static class BuilderExampleBuilder {
private String name;
private int age;
private java.util.ArrayList<String> occupations;

BuilderExampleBuilder() {
}

public BuilderExampleBuilder name(String name) {
this.name = name;
return this;
}

public BuilderExampleBuilder age(int age) {
this.age = age;
return this;
}

public BuilderExampleBuilder occupation(String occupation) {
if (this.occupations == null) {
this.occupations = new java.util.ArrayList<String>();
}

this.occupations.add(occupation);
return this;
}

public BuilderExampleBuilder occupations(Collection<? extends String> occupations) {
if (this.occupations == null) {
this.occupations = new java.util.ArrayList<String>();
}

this.occupations.addAll(occupations);
return this;
}

public BuilderExampleBuilder clearOccupations() {
if (this.occupations != null) {
this.occupations.clear();
}

return this;
}

public BuilderExample build() {
// complicated switch statement to produce a compact properly sized immutable set omitted.
// go to https://projectlombok.org/features/Singular-snippet.html to see it.
Set<String> occupations = ...;
return new BuilderExample(name, age, occupations);
}

@java.lang.Override
public String toString() {
return "BuilderExample.BuilderExampleBuilder(name = " + this.name + ", age = " + this.age + ", occupations = " + this.occupations + ")";
}
}
}

分享到

考虑使用静态工厂方法代替构造器(一)

考虑用静态工厂方法代替构造器

优点

它们有名称

  • 指的是方法的名称,能够准确描述返回的对象,对于多个构造方法的类可以使用不同的名称来描述返回对象
  • 对于构造方法参数的含义需要结合注释才能明白用哪一个构造器,并且多构造器的时候无法确切知道使用哪个构造器
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
package com.stardust.effective.role1;

/**
* Created by mike on 2017/12/3.
* 它们有名称
*/
public class Fruit {

private String color;

private String size;

private Fruit(String color,String size){
this.color=color;
this.size=size;
}

/**
* 通过方法名可以知道要构造什么样的对象
* @return
*/
public static Fruit getBigGreenFruit(){
return new Fruit("green","big");
}

public static Fruit getSmallRedFruit(){
return new Fruit("red","small");
}

public static Fruit getApple(){
return new Fruit("red","middle");
}

}

不必每次调用的时候都创建一个新对象

单例模式,对于一些不可变类可以使用这种方式,在上面那个例子中我对构造函数进行了私有化,可以认为是一个简单的单例,但还是需要升级优化,在后面单例的几种写法中展开说。
这种方式的一个优势即不必重复创建对象,在spring中大量使用单例这种设计模式来创建单一不可变对象。
书中还提到一个如果实例受控则可以通过==来判定是否为同一实例,这种写法比equals提升了性能。

术语:
实例受控的类(instance-controlled):在某个时刻只能有某些规定的该类的实例存在。

可以返回原返回类型的任何子类型的对象

文章中是以Collections为例的,一开始没有太理解,Collections是一个工具类,构造私有化的,不能直接实例化,Collection本身是接口,不能有静态工厂方法,所以委托给Collections这个工具类来提供生产构造.
下面贴一段Collection中静态工厂的例子,以List为例

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
/**
* Returns an immutable list containing only the specified object.
* The returned list is serializable.
*
* @param <T> the class of the objects in the list
* @param o the sole object to be stored in the returned list.
* @return an immutable list containing only the specified object.
* @since 1.3
*/
public static <T> List<T> singletonList(T o) {
return new SingletonList<>(o);
}

/**
* @serial include
*/
private static class SingletonList<E>
extends AbstractList<E>
implements RandomAccess, Serializable {

private static final long serialVersionUID = 3093736618740652951L;

private final E element;

SingletonList(E obj) {element = obj;}

public Iterator<E> iterator() {
return singletonIterator(element);
}

public int size() {return 1;}

public boolean contains(Object obj) {return eq(obj, element);}

public E get(int index) {
if (index != 0)
throw new IndexOutOfBoundsException("Index: "+index+", Size: 1");
return element;
}

// Override default methods for Collection
@Override
public void forEach(Consumer<? super E> action) {
action.accept(element);
}
@Override
public boolean removeIf(Predicate<? super E> filter) {
throw new UnsupportedOperationException();
}
@Override
public void replaceAll(UnaryOperator<E> operator) {
throw new UnsupportedOperationException();
}
@Override
public void sort(Comparator<? super E> c) {
}
@Override
public Spliterator<E> spliterator() {
return singletonSpliterator(element);
}
}

```

术语:基于接口的框架(interface-based framework):框架的对外访问与接入渠道是基于接口实现的。

#### 在创建参数化类型实例的时候,使代码更加简洁

``` java
// 当前做法
Map<String, List<String>> map new HashMap<String, List<String>>();
// 举例这样做会更简洁
Map<String, List<String>> map = HashMap.newInstance();
// java8已经可以直接这样写了
Map<String, List<String>> map = new HashMap<>();

缺点

类如果不含public或者protected的构造器, 就不能被子类化

  • 例如Collections类,不能被子类化,另一方面就是相当于鼓励复合(Composition),类似于用Collections这类的写法

无法与其他静态方法区分,不像构造方法名称必须为类名,可以使用一些惯用的名称来弥补这一劣势

  • valueOf() : 类型转换方法, 返回的实例与参数具有相同的值.
  • of() : valueOf()的一种更简洁的替代.
  • getInstance(): 返回的实例通过参数来描述, 对于单例来说, 该方法没有参数, 返回唯一的实例.
  • newInstance(): 像getInstance()一样, 但newInstance()能确保返回的每个实例都与其他实例不同.
  • getType() : 像getInstance()一样, Type表示返回的对象类型, 在工厂方法处于不同的类中的时候使用.
  • newType() : 和newInstance()一样, Type表示返回类型, 在工厂方法处于不同的类中的时候使用.
分享到

博客使用示例

Welcome to Hexo! This is your very first post. Check documentation for more info. If you get any problems when using Hexo, you can find the answer in troubleshooting or you can ask me on GitHub.

Quick Start

Create a new post

1
$ hexo new "My New Post"

More info: Writing

Run server

1
$ hexo s

More info: Server

Generate static files

1
$ hexo g

More info: Generating

Deploy to remote sites

1
$ hexo d

More info: Deployment

外链工厂图片

图片一:http://www.wailian.work/images/2018/04/20/1524194203156.jpg
图片二:http://www.wailian.work/images/2018/04/20/1524194162815.jpg
图片三:http://www.wailian.work/images/2018/04/20/1524194188729.jpg
图片四:http://www.wailian.work/images/2018/04/17/1523962657339.jpg
图片五:http://www.wailian.work/images/2018/04/17/1523962773687.jpg
图片六:http://www.wailian.work/images/2018/04/17/1523962729983.jpg
图片七:http://www.wailian.work/images/2018/04/17/1523962638880.jpg
图片八:http://www.wailian.work/images/2018/04/17/1523962692577.jpg
图片九:http://www.wailian.work/images/2018/04/17/1523932533990.jpg
图片十:http://www.wailian.work/images/2018/04/17/1523931297126.jpg

分享到

Mark Down语法

我在mac下用的Markdown编辑器是免费的Lite MWeb,从官方说明上摘抄下语法,以后备用

本文约定

如果有写 效果如下:, 在 MWeb 编辑状态下只有用 CMD + 4CMD + R 预览才可以看效果。

标题

Markdown 语法:

1
2
3
# 第一级标题 `<h1>` 
## 第二级标题 `<h2>`
###### 第六级标题 `<h6>`

效果如下:

第一级标题 <h1>

第二级标题 <h2>

第六级标题 <h6>

强调

Markdown 语法:

1
2
3
4
5
*这些文字会生成`<em>`*
_这些文字会生成`<u>`_

**这些文字会生成`<strong>`**
__这些文字会生成`<strong>`__

在 MWeb 中的快捷键为: CMD + UCMD + ICMD + B
效果如下:

这些文字会生成<em>
这些文字会生成<u>

这些文字会生成<strong>
这些文字会生成<strong>

换行

四个及以上空格加回车。
如果不想打这么多空格,只要回车就为换行,请勾选:Preferences - Themes - Translate newlines to <br> tags

列表

无序列表

Markdown 语法:

1
2
3
4
* 项目一 无序列表 `* + 空格键`
* 项目二
* 项目二的子项目一 无序列表 `TAB + * + 空格键`
* 项目二的子项目二

在 MWeb 中的快捷键为: Option + U
效果如下:

  • 项目一 无序列表 * + 空格键
  • 项目二
  • 项目二的子项目一 无序列表 TAB + * + 空格键
  • 项目二的子项目二

有序列表

Markdown 语法:

1
2
3
4
5
1. 项目一 有序列表 `数字 + . + 空格键`
2. 项目二
3. 项目三
1. 项目三的子项目一 有序列表 `TAB + 数字 + . + 空格键`
2. 项目三的子项目二

效果如下:

  1. 项目一 有序列表 数字 + . + 空格键
  2. 项目二
  3. 项目三
  4. 项目三的子项目一 有序列表 TAB + 数字 + . + 空格键
  5. 项目三的子项目二

任务列表(Task lists)

Markdown 语法:

1
2
- [ ] 任务一 未做任务 `- + 空格 + [ ]`
- [x] 任务二 已做任务 `- + 空格 + [x]`

效果如下:

  • 任务一 未做任务 - + 空格 + [ ]
  • 任务二 已做任务 - + 空格 + [x]

图片

Markdown 语法:

1
2
![GitHub set up](http://zh.mweb.im/asset/img/set-up-git.gif)
格式: ![Alt Text](url)

Control + Shift + I 可插入Markdown语法。
如果是 MWeb 的文档库中的文档,还可以用拖放图片、CMD + V 粘贴、CMD + Option + I 导入这三种方式来增加图片。
效果如下:

GitHub set up

MWeb 引入的特别的语法来设置图片宽度,方法是在图片描述后加 -w + 图片宽度 即可,比如说要设置上面的图片的宽度为 140,语法如下:

GitHub set up-w140

链接

Markdown 语法:

1
2
3
email <example@example.com>
[GitHub](http://github.com)
自动生成连接 <http://www.github.com/>

Control + Shift + L 可插入Markdown语法。
如果是 MWeb 的文档库中的文档,拖放或CMD + Option + I 导入非图片时,会生成连接。
效果如下:

Email 连接: example@example.com
连接标题Github网站
自动生成连接像: http://www.github.com/ 这样

区块引用

Markdown 语法:

1
2
3
某某说:
> 第一行引用
> 第二行费用文字

CMD + Shift + B 可插入Markdown语法。
效果如下:

某某说:

第一行引用
第二行费用文字

行内代码

Markdown 语法:

1
像这样即可:`<addr>` `code`

CMD + K 可插入Markdown语法。
效果如下:

像这样即可:<addr> code

多行或者一段代码

Markdown 语法:

1
2
3
4
5
6
function fancyAlert(arg) {
if(arg) {
$.facebox({div:'#foo'})
}

}

CMD + Shift + K 可插入Markdown语法。
效果如下:

1
2
3
4
5
6
function fancyAlert(arg) {
if(arg) {
$.facebox({div:'#foo'})
}

}

顺序图或流程图

Markdown 语法:

1
2
3
张三->李四: 嘿,小四儿, 写博客了没?
Note right of 李四: 李四愣了一下,说:
李四-->张三: 忙得吐血,哪有时间写。
1
2
3
4
5
6
7
8
st=>start: 开始
e=>end: 结束
op=>operation: 我的操作
cond=>condition: 确认?

st->op->cond
cond(yes)->e
cond(no)->op

效果如下( Preferences - Themes - Enable sequence & flow chart 才会看到效果 ):

1
2
3
张三->李四: 嘿,小四儿, 写博客了没?
Note right of 李四: 李四愣了一下,说:
李四-->张三: 忙得吐血,哪有时间写。
1
2
3
4
5
6
7
8
st=>start: 开始
e=>end: 结束
op=>operation: 我的操作
cond=>condition: 确认?

st->op->cond
cond(yes)->e
cond(no)->op

更多请参考:http://bramp.github.io/js-sequence-diagrams/, http://adrai.github.io/flowchart.js/

表格

Markdown 语法:

1
2
3
4
第一格表头 | 第二格表头
--------- | -------------
内容单元格 第一列第一格 | 内容单元格第二列第一格
内容单元格 第一列第二格 多加文字 | 内容单元格第二列第二格

效果如下:

第一格表头 第二格表头
内容单元格 第一列第一格 内容单元格第二列第一格
内容单元格 第一列第二格 多加文字 内容单元格第二列第二格

删除线

Markdown 语法:

加删除线像这样用: 删除这些

效果如下:

加删除线像这样用: 删除这些

分隔线

以下三种方式都可以生成分隔线:




效果如下:




MathJax

Markdown 语法:

1
2
3
4
5
6
7
8
块级公式:
$$ x = \dfrac{-b \pm \sqrt{b^2 - 4ac}}{2a} $$

\\[ \frac{1}{\Bigl(\sqrt{\phi \sqrt{5}}-\phi\Bigr) e^{\frac25 \pi}} =
1+\frac{e^{-2\pi}} {1+\frac{e^{-4\pi}} {1+\frac{e^{-6\pi}}
{1+\frac{e^{-8\pi}} {1+\ldots} } } } \\]

行内公式: $\Gamma(n) = (n-1)!\quad\forall n\in\mathbb N$

效果如下(Preferences - Themes - Enable MathJax 才会看到效果):

块级公式:
$$ x = \dfrac{-b \pm \sqrt{b^2 - 4ac}}{2a} $$

\[ \frac{1}{\Bigl(\sqrt{\phi \sqrt{5}}-\phi\Bigr) e^{\frac25 \pi}} =
1+\frac{e^{-2\pi}} {1+\frac{e^{-4\pi}} {1+\frac{e^{-6\pi}}
{1+\frac{e^{-8\pi}} {1+\ldots} } } } \]

行内公式: $\Gamma(n) = (n-1)!\quad\forall n\in\mathbb N$

脚注(Footnote)

Markdown 语法:

1
这是一个脚注:[^sample_footnote]

效果如下:

这是一个脚注:^sample_footnote

注释和阅读更多

查看更多

分享到