天天看点

设计原则 - 接口隔离原则(ISP),让你的代码更优雅

作者:迷路的架构师

接口隔离原则(Interface Segregation Principle,ISP)是指一个类对另一个类的依赖应该建立在最小的接口上,而不是依赖于不需要的接口。该原则的目的是减少接口间的耦合性,提高系统的灵活性和可维护性。

接口隔离原则可以通过以下几个方面来实现:

  1. 接口要尽量小,避免出现臃肿的接口,一个接口只服务于一个子模块或业务逻辑。
  2. 接口中的方法尽量少,接口中只包含对外公布的方法,即接口方法应该是最小集合。
  3. 接口要高内聚,不同的接口要根据业务逻辑划分,相互之间要保持独立,避免出现多余的方法。
  4. 尽量细化接口,接口中的方法应该尽量细化,可以根据不同的业务场景设计多个小接口,而不是设计一个大接口,这样可以降低客户端的复杂度。

正例

以下是一个Java示例,假设我们有一个接口Animal和一个实现该接口的类Dog和Cat,其中Animal接口中定义了两个方法:eat()和sleep()。

public interface Animal {
    void eat();
    void sleep();
}

public class Dog implements Animal {
    @Override
    public void eat() {
        System.out.println("Dog is eating...");
    }

    @Override
    public void sleep() {
        System.out.println("Dog is sleeping...");
    }
}

public class Cat implements Animal {
    @Override
    public void eat() {
        System.out.println("Cat is eating...");
    }

    @Override
    public void sleep() {
        System.out.println("Cat is sleeping...");
    }
}
           

在这个例子中,Animal接口尽可能地遵循了接口隔离原则,只定义了两个方法,而不是包含其他不需要的方法。同时,Dog和Cat类实现了Animal接口,只实现了需要的eat()和sleep()方法,而没有实现其他不需要的方法。

我们可以使用下面的代码创建一个Animal对象,分别使用Dog和Cat对象实现Animal接口,并调用它们的eat()和sleep()方法:

Animal animal = new Dog();
animal.eat();   // 输出:Dog is eating...
animal.sleep(); // 输出:Dog is sleeping...

animal = new Cat();
animal.eat();   // 输出:Cat is eating...
animal.sleep(); // 输出:Cat is sleeping...
           

可以看到,Animal接口尽可能地遵循了接口隔离原则,只定义了需要的方法,而Dog和Cat类也只实现了需要的方法,这样可以降低客户端的复杂度,并且提高系统的灵活性和可维护性。

反例

假设有一个接口Animal,定义了两个方法eat()和fly():

public interface Animal {
    void eat();
    void fly();
}           

现在我们有一个实现该接口的类Bird:

public class Bird implements Animal {
    @Override
    public void eat() {
        System.out.println("Bird is eating...");
    }

    @Override
    public void fly() {
        System.out.println("Bird is flying...");
    }
}           

这看起来似乎没有问题,但是接口Animal中定义的fly()方法并不是所有动物都具备的行为,比如像狗、猫等动物是不会飞的,如果我们让这些动物也实现Animal接口,就必须强制让它们实现fly()方法,这违反了接口隔离原则。

假设现在我们要让Dog类也实现Animal接口:

public class Dog implements Animal {
    @Override
    public void eat() {
        System.out.println("Dog is eating...");
    }

    @Override
    public void fly() {
        // Dog不会飞,该方法无法实现,但是却必须实现
        System.out.println("Dog is flying...");
    }
}           

由于Dog类不会飞,所以它无法正确地实现fly()方法,但是由于接口的定义,Dog类必须实现该方法,这会导致Dog类在实现Animal接口时出现问题,违反了接口隔离原则。

因此,如果我们按照接口隔离原则进行设计,Animal接口应该只定义必须的方法,避免出现不必要的方法,这样可以避免实现类出现不必要的麻烦,提高系统的灵活性和可维护性。

继续阅读