《Effective java》笔记(第二版) --第四章(20-22)

个人笔记

第四章 ——类和接口


第二十条: 类层次优于标签类

类层次代表会有更多的类被创建,之间有一种继承关系,构成层次关系,标签类(tagged class)则像一个大杂烩,标签类中有各式各样的成员,通过公共暴露的接口往外界提供作用,伴随着switch等分之判断和多余的使用成本(使用其中一个功能必须吧里面的玩意全实例化),违反了面向对象的专一原则,在java中,则使用类层次来替换,使得每次调用不会使用过多的额外代价,并且可读性也更好,反映出类和类之间的层次关系,也能获得编译期的类型检查支持
比如说

public class MyUtil {
    enum Util {
        CHUIZI, BANSHOU, FUTOU
    };// 我手头的工具

    private Util util;

    public MyUtil(Util util) {//传递工具Util枚举类型
        this.util = util;
    }

    String sound() {
        switch (util) {
        case CHUIZI:
            return "dang dang dang";
        case BANSHOU:
            return "gaz gaz gaz";
        case FUTOU:
            return "k k k k";
        default:
            throw new IllegalArgumentException("argument type error");
        }
    }
}

可见如果我要使用CHUIZI的话,就得对其他的成员BANSHOU的额外调用,而且在sound函数中还有一个难看的switch分支,每次添加新的工具就必须同时更新switch分支

而接下来的类层次则会更加清晰,增加起来也会很方便

abstract class Util {
    abstract String sound();
}

class ChuiZi extends Util {

    @Override
    String sound() {
        return "dang dang dang";
    }

}

class BANSHOU extends Util {

    @Override
    String sound() {
        return "gaz gaz gaz";
    }
}
...

abstract 无非是强制实现,构成层次关系,这样扩展我们的工具的时候就不再耦合,Effective c++中也提到过,不要过分设计,设计往往需要你思考下是否可行。

Effective java原话总结

/*简而言之,标签类很少有适用的时候,当你想要编写一个包含显式标签域的类时,应该考虑一下,这个标签是否可以被取消,这个类是否可以用类层次代替,当你遇到一个包含标签域的现有类时,就要考虑将它重构到一个层次结构中去*/
第二十一条:用函数对象表示策略

(常和泛型参数一起组合)
函数对象,函数对象,会让我想起C++ 的operator ()
然后这样重载的对象吧它丢到泛型参数中去,然后作为函数一般的使用,也就是STL中的仿函数了,还有lamda表达式,c11来着?忘记了,例子差不多这样

sort(v.begin(), v.end(), [](int a, int b) {return  a > b; });

有趣的语法糖,java 1.8也有这样的功能,让语法更优雅

思考下java的compare 和 comparator接口,一个类的作者自己写,一个弥补没有的功能,然后传递给一些容器或者工具类去进行操作,比如Util包的Arrays的一个函数

public static <T> int binarySearch(T[] a,
                                   int fromIndex,
                                   int toIndex,
                                   T key,
                                   Comparator<? super T> c)

这个comparator是一种策略接口,和c++的仿函数的思想一模一样,不过java是用接口实现功能,而c++是重载()
那么String就是一个包含策略接口的策略类(先无视策略接口实例以外的东西)

    public static final Comparator<String> CASE_INSENSITIVE_ORDER
                                         = new CaseInsensitiveComparator();

用String.CASE_INSENSITIVE_ORDER来吧接口实例传递给要使用的排序的类,用简介便于理解的名字用于给类的用户理解和调用,
这个字段是static 所以不用额外的构造,只加载一次,因为是final,所以无法修改赋值,不会对已经使用这个策略的其他类造成影响,这是必须的,当你有很多种方案要操作一些东西的时候,就应该考虑这个策略模式,吧策略接口作为一个static final 的域(名字通俗易懂)给类用户使用

第二十二条:优先考虑静态成员

static和public总是组合在一起,而内部类能够访问外层的类,static 修饰的内部类不需要外围的实例,就好像是它们是偶尔被丢进这个外部类的一样,普通的内部类调用会伴随着外部类的实例化成本,也无法保证类的作者有没有对内部类和外部类进行耦合,导致结果也无法肯定,在考虑这个内部类是否真的需要访问外部类的时候,如果并不是的话, 就该是static,否则就付出额外的代价

思考如何才能减少构建,或者使类用户使用这个类更加舒适,这就是这个条目的内容

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值