EffectiveJava——类与接口4.md

第19条:接口只用于定义类型

当类实现接口时,接口就充当可以引用这个类的实例的类型。因此类实现了某一个接口,就表明客户端可以对这个类的实例实施某些操作,为了任何其他目的而定义接口是不恰当的。

避免使用常量接口

如果要使用常量,有以下合理的方法:
- 如果这个常量不某个现有类或接口相关,应该把常量定义在这个类或者接口中。
- 如果这些常量最好被看做枚举,就使用枚举定义
- 应该使用不可实例化的工具类来导出常量

总而言之,接口只应该用来定义类型,不应该用来导出常量。

第20条:类层次优先于标签类

有时候,可能会遇到带有两种风格甚至更多风格的实例的类,并包含表示实例风格的标签(tag)域,例如下面一个类,能表示圆形或者方形:

package com.ztiany.effect.three;

/**
 * Created by Administrator on 2016-03-06.
 */
public class Figure {

    enum Shape {
        rectangle, circle
    }

    final Shape shape;

    double radius;

    double height;
    double width;

    Figure(double radius) {
        shape = Shape.circle;
        this.radius = radius;
    }

    Figure(double width, double height) {
        shape = Shape.rectangle;
        this.height = height;
        this.width = width;
    }


    double area() {
        double area = 0;
        switch (shape) {
            case circle:
                area = height * width;
                break;
            case rectangle:
                area = Math.PI * (radius * radius);
                break;
        }
        return area;
    }

}

这种标签类有着许多的缺点,充斥着样板代码,内存暂用,如果要增加标签,又要写很多条件语句,….

所以我们应该使用子类型化,标签类正是类层次的一种简单效仿

将标签类转变为层次类,抽取共性行为,这里只有area

public abstract class Figure {

    public abstract  double area();


}

class Circle extends Figure{

    private final double radius;
    @Override
    public double area() {
        return  Math.PI * (radius * radius);
    }

    Circle(double radius) {
        this.radius = radius;
    }
}

class Rectangle extends Figure{
    private final double width;
    private final double height;
    Rectangle(double width, double height) {
        this.width = width;
        this.height = height;
    }

    @Override
    public double area() {
        return  height * width;;
    }
}

这种类层次纠正了标签类的所有缺点,代码简单而且清晰。没有多个构造器的影响,每个域都可以定义为为final的,没有了switch语句,而且更加易于拓展

类层次的另一个好处在于:他们可以反应类型之间本质上的层次关系。

public Square extends Rectangle{
...
}

简而言之:标签类很少有适用的时候。

第21条:用函数对象表示策略

在TreeSet创建时我们可以传入一个比较器:

TreeSet(Comparator<? super E> comparator) 
          构造一个新的空 TreeSet,它根据指定比较器进行排序。

TreeSet会根据比较器实现的不同而对存入元素进行不同的排序,这正是策略(strategy)模式的一个例子

一般在java中实现策略模式,首先声明一个接口来表示该策略,并且为每个具体的策略声明一个实现了接口的类。

第22条:优先考虑静态成员类

嵌套(nested)是指被定义在另一个类的内部的类,嵌套类存在的目的应该只是为了他的外围(enclosing)提供服务,如果嵌套类可能用于其他的某个环境中,他就应该是顶层类(top_level),嵌套类有四种:
- 静态成员类(static member)
- 非静态成员类(nostatic member)
- 匿名类(anonymous)
- 局部类(local)

静态成员类是最简单的一种类,静态成员类的一种常见用法是作为共有的辅助类,仅当它与外部类一起使用才有意义。
非静态成员类和静态成员类的区别:
- 非静态成员类都隐含着与外围类的一个实例相关联,非静态成员类可以调用外围泪的方法,访问外围类的成员,利用修饰过的this可以获取外围类的实例引用(Android中常因此而发生内存泄漏)
- 如果一个嵌套成员类要独立于外围类的实例而存在,那么这个嵌套成员类必须是静态的。非静态成员类不可能独立于它的外围类的实例而独立存在。

非静态成员类与他的外围类的关系的创建都是需要时间开销的。并且消耗非静态成员类实例的空间
如果声明成员类不要求访问外围实例,就始终要它定义为静态的。

匿名类只有出现在非静态的环境中才有他外围类的实例,匿名类不应该过长,10或者更少为好,一般用于动态的创建函数对象。

局部类用的最少,规则与匿名类一样。

你可能感兴趣的:(EffectiveJava——类与接口4.md)