1、考虑用静态工厂方法代替构造器(effective java)

目录检索

第2章 创建和销毁对象
第1条:考虑用静态工厂方法代替构造器
第2条:遇到多个构造器参数时要考虑用构建器
第3条:用私有构造器或者枚举类型强化Singleton属性
第4条:通过私有构造器强化不可实例化的能力
第5条:避免创建不必要的对象
第6条:消除过期的对象引用
第7条:避免使用终结方法
第3章 对于所有对象都通用的方法
第8条:覆盖equals时请遵守通用约定
第9条:覆盖equals时总要覆盖hashCode
第10条:始终要覆盖toString
第11条:谨慎地覆盖clone
第12条:考虑实现Comparable接口
第4章 类和接口
第13条:使类和成员的可访问性最小化
第14条:在公有类中使用访问方法而非公有域
第15条:使可变性最小化
第16条:复合优先于继承
第17条:要么为继承而设计,并提供文档说明,要么就禁止继承
第18条:接口优于抽象类
第19条:接口只用于定义类型
第20条:类层次优于标签类
第21条:用函数对象表示策略
第22条:优先考虑静态成员类
第5章 泛型
第23条:请不要在新代码中使用原生态类型
第24条:消除非受检警告
第25条:列表优先于数组
第26条:优先考虑泛型
第27条:优先考虑泛型方法
第28条:利用有限制通配符来提升API的灵活性
第29条:优先考虑类型安全的异构容器
第6章 枚举和注解
第30条:用enum代替int常量
第31条:用实例域代替序数
第32条:用EnumSet代替位域
第33条:用EnumMap代替序数索引
第34条:用接口模拟可伸缩的枚举
第35条:注解优先于命名模式
第36条:坚持使用Override注解
第37条:用标记接口定义类型
第7章 方法
第38条:检查参数的有效性
第39条:必要时进行保护性拷贝
第40条:谨慎设计方法签名
第41条:慎用重载
第42条:慎用可变参数
第43条:返回零长度的数组或者集合,而不是:null
第44条:为所有导出的API元素编写文档注释
第8章 通用程序设计
第45条:将局部变量的作用域最小化
第46条:for-each循环优先于传统的for循环
第47条:了解和使用类库
第48条:如果需要精确的答案,请避免使用float和double
第49条:基本类型优先于装箱基本类型
第50条:如果其他类型更适合,则尽量避免使用字符串
第51条:当心字符串连接的性能
第52条:通过接口引用对象
第53条:接口优先于反射机制
第54条:谨慎地使用本地方法
第55条:谨慎地进行优化
第56条:遵守普遍接受的命名惯例
第9章 异常
第57条:只针对异常的情况才使用异常
第58条:对可恢复的情况使用受检异常,对编程错误使用运行时异常
第59条:避免不必要地使用受检的异常
第60条:优先使用标准的异常
第61条:抛出与抽象相对应的异常
第62条:每个方法抛出的异常都要有文档
第63条:在细节消息中包含能捕获失败的信息
第64条:努力使失败保持原子性
第65条:不要忽略异常
第10章 并发
第66条:同步访问共享的可变数据
第67条:避免过度同步
第68条:executor和task优先干线程
第69条:并发工具优先于wait和notify
第70条:线程安全性的文档化
第71条:慎用延迟初始化
第72条:不要依赖于线程调度器
第73条:避免使用线程组
第11章 序列化
第74条:谨慎地实现Serializable接口
第75条:考虑使用自定义的序列化形式
第76条:保护性地编写readObject方法
第77条:对于实例控制,枚举类型优先于readResolve
第78条:考虑用序列化代理代替序列化实例

考虑静态构造方法

这里的静态构造方法不等于设计模式中的工厂模式

public static Boolean valueOf(boolean b) {
    return b ? Boolean.TRUE : Boolean.FALSE;
}

优点:

第一个优势是有名称

对于同一个对象,它的构造函数名字是确定的,有时候你需要基于这个类的自定义对象,采用这种静态构造方法,命名的时候可以很清楚的把这个对象的特点说清楚。

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

你可以缓存起来,进行重复利用,每次返回的时候都返回同一个对象,如上面的代码所示,并没有使用new,直接返回的是已经有的对象

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

适用于基于接口的框架。而且可以使API返回的对象的类是私有的(使用构造函数肯定不行)。

服务者提供框架

静态工厂方法返回的对象所属的类编写包含该静态工厂方法的类时可不存在,构成了服务者提供框架

//服务提供者接口,用来提供服务
//这个接口时可选的,如果没有,下面的Map集合就可以直接存放Service对象
public interface Provider {
    Service newService();
}
//服务接口, 用来写具体的服务内容
public interface Service {
    // Service-specific methods go here
}
public class Services {
    private Services() {
    } // Prevents instantiation (Item 4)

    // Maps service names to services
    //服务的注册和访问
    //用一个Map来存放提供这的名字和提供者的对象
    private static final Map<String, Provider> providers = new ConcurrentHashMap<String, Provider>();
    public static final String DEFAULT_PROVIDER_NAME = "<def>";

    // Provider registration API
    //注册默认的提供者
    public static void registerDefaultProvider(Provider p) {
        registerProvider(DEFAULT_PROVIDER_NAME, p);
    }
    //所谓注册就是在加入Map
    public static void registerProvider(String name, Provider p) {
        providers.put(name, p);
    }

    // Service access API
    //使用这个方法创建实例
    public static Service newInstance() {
        return newInstance(DEFAULT_PROVIDER_NAME);
    }

    //创建的时候看缓存里有没有provider
    public static Service newInstance(String name) {
        Provider p = providers.get(name);
        if (p == null)
            throw new IllegalArgumentException(
                    "No provider registered with name: " + name);
        return p.newService();
    }
}

测试

public class Test {
    public static void main(String[] args) {
        //测试的时候先注册,然后在再创建相应地对象,这里的provider的使用内部类
        //由provider返回具体的service实例
        // Providers would execute these lines
        Services.registerDefaultProvider(DEFAULT_PROVIDER);
        Services.registerProvider("comp", COMP_PROVIDER);
        Services.registerProvider("armed", ARMED_PROVIDER);

        // Clients would execute these lines
        //调用Service的toString方法
        Service s1 = Services.newInstance();
        Service s2 = Services.newInstance("comp");
        Service s3 = Services.newInstance("armed");
        System.out.printf("%s, %s, %s%n", s1, s2, s3);
    }

    private static Provider DEFAULT_PROVIDER = new Provider() {
        public Service newService() {
            return new Service() {
                @Override
                public String toString() {
                    return "Default service";
                }
            };
        }
    };

    private static Provider COMP_PROVIDER = new Provider() {
        public Service newService() {
            return new Service() {
                @Override
                public String toString() {
                    return "Complementary service";
                }
            };
        }
    };

    private static Provider ARMED_PROVIDER = new Provider() {
        public Service newService() {
            return new Service() {
                @Override
                public String toString() {
                    return "Armed service";
                }
            };
        }
    };
}

在创建泛型的时候,可以使代码更简单

例如:

//参数你不用再后面重新写一遍了,但实际上HaspMap没有这个方法,这里只是举例说明问题
Map<String, List<String> m = HashMap.newInstance();

缺点:

类如果不含有公有的或者受保护的构造器,就不能被子类化

与其他静态方法没有任何区别(不像构造函数那样地位很高)

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值