最近由于要开发中间件。可是写了好几个版本,都感受不怎么好。比起一些大厂的实现,感受在代码架构的设计,java语言的基础知识上面仍是掌握的不够牢靠。因而打算重读一些比较经典的书籍。《Effective Java》就是其中一本。java
主要讲解了对象的建立和销毁。多用工厂和建造者模式,尽可能避免冗长的构造方法。其中对于单例的建立,提到了有关在单例序列化/反序列化的时候两个个陷阱:架构
public class User implements Serializable {
private static final long serialVersionUID = -672817526808710807L;
private static final User user = new User();
private String age;
private String name;
public String getAge() {
return age;
}
public void setAge(String age) {
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
private User() {
this.age = "3";
this.name = "java";
}
public static User getInstance() {
return user;
}
private Object readResolve() {
return user;
}
}
public class SerializableDemo {
@SuppressWarnings("resource")
public static void main(String[] args) throws FileNotFoundException, IOException, ClassNotFoundException {
ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("/Users/tiny/Desktop/test.txt"));
out.writeObject(User.getInstance());
FileInputStream fis = new FileInputStream(new File("/Users/xujianxing/Desktop/test.txt"));
ObjectInputStream ois = new ObjectInputStream(fis);
User u = (User) ois.readObject();
System.out.println(u.getName());
if(User.getInstance()==u){
System.out.println("equals");
}
else{
System.out.println("not equals");
}
}
}复制代码
输出not equals。
将User对象,稍稍改造:优化
package demo;
import java.io.Serializable;
public class User implements Serializable {
private static final long serialVersionUID = -672817526808710807L;
private static final User user = new User();
private String age;
private String name;
public String getAge() {
return age;
}
public void setAge(String age) {
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
private User() {
this.age = "3";
this.name = "java";
}
public static User getInstance() {
return user;
}
private Object readResolve() {
return user;
}
}
package demo;
import java.io.Serializable;
public class User implements Serializable {
private static final long serialVersionUID = -672817526808710807L;
private static final User user = new User();
private String age;
private String name;
public String getAge() {
return age;
}
public void setAge(String age) {
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
private User() {
this.age = "3";
this.name = "java";
}
public static User getInstance() {
return user;
}
private Object readResolve() {
return user;
}
}复制代码
增长一个readResolve
方法。ui
AccessibleObject.setAccessible
强制调用私有构造器。就像这样:public class SerializableDemo {
@SuppressWarnings("resource")
public static void main(String[] args) throws InvocationTargetException, InstantiationException, IllegalAccessException, IllegalArgumentException {
Class<?> clazz = User.getInstance().getClass();
Constructor[] constructors = clazz.getDeclaredConstructors();
for (Constructor constructor : constructors) {
System.out.println(constructor.getName());
constructor.setAccessible(true); // AccessibleObject
System.out.println(constructor.newInstance(null));
System.out.println(User.getInstance());
}
}
}复制代码
若是要抵御这种攻击。能够修改构造器,但在构造器中抛出异常不是一个好的实践。而且会破坏final域。this
在某些状况下,能够利用建造者模式来大幅优化业务代码,使得业务代码看起来也十分优雅,而且具备很强的扩展性。好比有一个摄影师系统。摄影师的积分规则以下:spa
若是直接在业务系统里面计算代码,一但业务改变,那么业务中的代码也会改变,这样就违背了“对扩展开放,对修改关闭"的原则。使用建造者模式能够减小对业务系统的入侵。设计
public class PointRule {
//积分变更记录
private Multimap<String, String> myMultimap =null;
private int changeTotal;
public int getChangeTotal() {
return changeTotal;
}
public void setChangeTotal(int changeTotal) {
this.changeTotal = changeTotal;
}
private PointRule(int changeTotal,Multimap<String, String> record) {
this.changeTotal = changeTotal;
this.record=record;
}
private static final int PLUS_NEW_ORDER = 10;
private static final int PLUS_ADD_SHEET = 1;
private static final int PLUS_COMMENT_FIVE = 5;
private static final int PLUS_COMMENT_FOUR = 10;
private static final int PLUS_UPLOAD_CURRENT_DAY = 10;
private static final int PLUS_UPLOAD_SECOND_DAY = 5;
private static final int PLUS_BID_FAIL = 2;
private static final int PLUS_UPLOAD_WORK = 1;
private static final int REDUCE_UPLOAD_DELAY = -5;
public static class Builder {
private int total = 0;
Multimap<String, String> myMultimap = ArrayListMultimap.create();
public static Builder getInstance() {
return new Builder();
}
public Builder plusNewOrder(String orderId) {
total += PLUS_NEW_ORDER;
this.record.put("orderId", "plusNewOrder");
return this;
}
public Builder plusAddSheet(String orderId) {
total += PLUS_ADD_SHEET;
this.record.put("orderId", "plusAddSheet");
return this;
}
public Builder plusCommentFive(String orderId) {
total += PLUS_COMMENT_FIVE;
this.record.put("orderId", "plusCommentFive");
return this;
}
public Builder plusCommentFour() {
total += PLUS_COMMENT_FOUR;
this.record.put("orderId", "plusCommentFour");
return this;
}
public Builder plusUploadCurrentDay() {
total += PLUS_UPLOAD_CURRENT_DAY;
this.record.put("orderId", "plusUploadCurrentDay");
return this;
}
public Builder plusUploadSecondDay() {
total += PLUS_UPLOAD_SECOND_DAY;
this.record.put("orderId", "plusUploadSecondDay");
return this;
}
public Builder plusBidFail(String orderId) {
total += PLUS_BID_FAIL;
this.record.put("orderId", "plusBidFail");
return this;
}
public Builder plusUploadWork(String orderId) {
total += PLUS_UPLOAD_WORK;
this.record.put("orderId", "plusUploadWork");
return this;
}
public Builder reduceUploadDelay(String orderId) {
total += REDUCE_UPLOAD_DELAY;
this.record.put("orderId", "reduceUploadDelay");
return this;
}
public PointRule build() {
PointRule pointRule = new PointRule(this.total,this.record);
return pointRule;
}
}
}复制代码
假设有一个Service:code
public class PhotographerService {
public void userConfirmSheetOrder(){
//用户收片的逻辑。
PointRule.Builder buidler=PointRule.Builde.getInstance();
if(当天收片){
buidler.plusCurrentDay();
}
if(修了10张片){
(for int i=0; i<10;i++){
buidler.plusAddSheet();
}
//其余的业务逻辑
最后获得此次要改变的分数:
PointRule rule=buidler.builder();
//若是要将积分变更的记录入库。那么能够循环PointRule 的map对象。
}复制代码
对于积分变更记录,可使用迭代器模式。当让这个例子只是一个举例说明。比起直接在service里面算积分,是否是会好不少呢?中间件