第1条:用静态工厂方法代替构造器
优点:
- 相较于构造方法,通过静态工厂创建对象能够使得用户对类的使用更加直观(后续开发中进行尝试)
public static Child newChild(int age, int weight) {
Child child = new Child();
child.weight = weight;
child.age = age;
return child;
}
替代 new Child(int age,int weight)
- 生成单例,避免每次都创建对象,浪费空间(视情况选择)
- 可以返回子类型对象,根据自己的需要进行返回 ()
public static Father newChild(int age, int weight) {
Child child = new Child();
child.weight = weight;
child.age = age;
return child;
}
4.返回的类可以随着每次调用而动态变化,这取决于静态工厂的方法的参数值。可根据传入不同的参数或者值,来返回不同的类,即简单工厂模式
5.静态工厂返回的类可以不存在
例子:服务提供者框架
//四大组成之一:服务接口
public interface LoginService {//这是一个登录服务
public void login();
}
//四大组成之二:服务提供者接口
public interface Provider {//登录服务的提供者。通俗点说就是:通过这个newLoginService()可以获得一个服务。
public LoginService newLoginService();
}
/**
* 这是一个服务管理器,里面包含了四大组成中的三和四
* 解释:通过注册将 服务提供者 加入map,然后通过一个静态工厂方法 getService(String name) 返回不同的服务。
*/
public class ServiceManager {
private static final Map<String, Provider> providers = new HashMap<String, Provider>();//map,保存了注册的服务
private ServiceManager() {
}
//四大组成之三:提供者注册API (其实很简单,就是注册一下服务提供者)
public static void registerProvider(String name, Provider provider) {
providers.put(name, provider);
}
//四大组成之四:服务访问API (客户端只需要传递一个name参数,系统会去匹配服务提供者,然后提供服务) (静态工厂方法)
public static LoginService getService(String name) {
Provider provider = providers.get(name);
if (provider == null) {
throw new IllegalArgumentException("No provider registered with name=" + name);
}
return provider.newLoginService();
}
}
想要增加服务时只需要实现服务提供者接口、服务接口,然后约定一个服务名就可以了。
第二条 遇到多个构造器参数时要考虑使用构建器
1.重叠构造器
为各种参数配置多个构造器,缺点:参数过多时,实现繁琐
2.javaBeans
new 一个无参的对象,再通过set进行设置参数,缺点:线程安全无法保证
3.建造者模式(Builder)
-
需要一个构造函数用来存放Builder,将Builder的参数存放到对象中
private Person(Builder builder) { this.name = builder.name; this.homeAddr = builder.homeAddr; this.tel = builder.tel; this.workAddr = builder.workAddr;}
-
需要一个内部静态类Builder,参数与person相同,并且存在与参与名相同的方法,作用的将值存放到Builder对象中,并返回
public static class Builder {
private String name;
private String workAddr;
private String homeAddr;
private int tel;
public Builder() {}
public Builder name(String name) {
this.name = name;
return this;
}
......
-
内部静态类Builder中,还需要一个builder方法,将Builder对象传入后,返回对象
public Person build() { return new Person(this);}
-
创建对象的方法
Person person = new Person.Builder.name().builder();
第三条 用私有构造器或者枚举类型强化Singleton属性
单例实现的四种方式:
-
懒汉式
-
饿汉式
-
DCL
-
枚举类型,优点是防止反射,序列化new对象 ,最佳方法
public enum EnumTest { IN; private String name; private EnumTest(){} public String getName() { return name; } public void setName(String name) { this.name = name; } }
public static void main(String[] args) throws Exception { EnumTest in = EnumTest.IN; in.setName("111");}
第四条 通过私有构造器强化不可实例化的能力
private 的构造方法,使得不可被外部实例化 。。。但是能被反射实例化
第五条 优先考虑依赖注入来引用资源
通过传入对象来实现,而不直接指定特定对象。
public class Person {
Phone phone = IPhone.getInstance();
public void playGame() {
phone.playGame();
}
public static Person getInstance() {
return new Person();
}
}
依赖注入
public class Person {
Phone phone;
public void playGame() {
phone.playGame();
}
// 构造方法注入
private Person(Phone phone) {
this.phone = phone;
}
}
第六条 避免创建不必要的对象
1.字符串最好抽成常量,不要出现魔法值
2.不要每次都创建对象,根据情况进行优化,但需要考虑对象的拷贝问题
3.自动装箱,优先使用基本数据类型,而不是装箱类,装箱类是对象,但是在网络请求时,最好使用装箱类,因为装箱类实现了序列化。
第七条 消除过期的对象引用
1.类自己管理内存时,需要警惕内存泄漏问题
2.缓存可以放到WeakHashMap,弱引用,当对象不被引用就被回收
3.监听器和其他回调
第八条 避免使用终结方法和清除方法
第九条 try-with-resources 优先于 try-finally
try-finally 当try阶段和finally阶段都出现异常时,只能显示finally的异常
public class Connection implements AutoCloseable {
public void sendData() throws Exception {
throw new IOException("send data");
}
@Override
public void close() throws Exception {
throw new Exception("close");
}
}
public static void main(String[] args) throws Exception {
Connection connection = null;
try{
connection = new Connection();
connection.sendData();
}finally {
if(connection!= null){
connection.close();
}
}
}
异常信息
Exception in thread "main" java.lang.Exception: close
at com.example.demo.controller.Connection.close(Connection.java:21)
at com.example.demo.controller.UserController.main(UserController.java:24)
换成 try-with-resource写法 就是将资源生成语句写在try()中
public static void main(String[] args) {
try (Connection connection = new Connection()) {
connection.sendData();
} catch (Exception e) {
e.printStackTrace();
}
}
异常信息 两次异常信息都被打印出来
java.io.IOException: send data
at com.example.demo.controller.Connection.sendData(Connection.java:16)
at com.example.demo.controller.UserController.main(UserController.java:18)
Suppressed: java.lang.Exception: close
at com.example.demo.controller.Connection.close(Connection.java:20)
at com.example.demo.controller.UserController.main(UserController.java:19)