今天在学习依赖注入的时候,碰到这个问题:当一个接口有多个实现类的时候,我们调用方法的时候,通常是调用接口,而不是直接调用实现类。这是因为接口用来定义申明,而实现类可以是多种变化的,所以通常我们在调用时写接口,而不是具体的实现类,可以降低代码的耦合性,提高重用度

以下是遵循接口编程的一些好处:

1. 松耦合(Loose Coupling):通过面向接口编程,调用方与实现方之间的依赖关系变得松散。调用方只需要知道接口的方法和约定,而不需要了解具体的实现细节。这样可以降低代码的耦合度,使系统更加灵活和可维护。

2. 可替换性(Replaceability):使用接口编程可以实现组件的可替换性。如果一个接口有多个实现类,你可以在不修改调用方代码的情况下,轻松地切换不同的实现类。这种可替换性对于系统的扩展性和测试性都非常有价值。

3. 单一职责原则(Single Responsibility Principle):接口可以将不同的功能和责任进行划分,每个实现类只需关注自己的具体实现。这样可以提高代码的可读性、可维护性和可测试性,使系统更加清晰和易于理解。

4. 接口抽象性(Interface Abstraction):接口可以提供一种抽象层次,隐藏实现类的内部细节。这样可以将关注点集中在接口定义和使用上,而不需要关心具体的实现细节。这种抽象性有助于提高代码的可理解性和可复用性。

那么当一个接口有多个实现类时,我们怎么知道调用哪个实现类呢?以下是几种常见的示例,展示如何实现接口并调用具体的实现类: 

1、显式实例化调用:直接通过接口类引用实现类的对象

interface MyInterface {
    void myMethod();
}

class MyClass1 implements MyInterface {
    @Override
    public void myMethod() {
        System.out.println("MyClass1 implements MyInterface");
    }
}

class MyClass2 implements MyInterface {
    @Override
    public void myMethod() {
        System.out.println("MyClass2 implements MyInterface");
    }
}

public class Main {
    public static void main(String[] args) {
        MyInterface obj1 = new MyClass1();
        obj1.myMethod(); // 输出:"MyClass1 implements MyInterface"

        MyInterface obj2 = new MyClass2();
        obj2.myMethod(); // 输出:"MyClass2 implements MyInterface"
    }
}

2、在配置文件中决定调用

interface MyInterface {
    void myMethod();
}

class MyClass1 implements MyInterface {
    @Override
    public void myMethod() {
        System.out.println("MyClass1 implements MyInterface");
    }
}

class MyClass2 implements MyInterface {
    @Override
    public void myMethod() {
        System.out.println("MyClass2 implements MyInterface");
    }
}

public class Main {
    public static void main(String[] args) {
        String className = getConfiguredClassName(); // 从配置文件或属性文件获取类名

        try {
            Class<?> clazz = Class.forName(className);
            MyInterface obj = (MyInterface) clazz.newInstance();
            obj.myMethod();
        } catch (ClassNotFoundException | InstantiationException | IllegalAccessException e) {
            e.printStackTrace();
        }
    }

    private static String getConfiguredClassName() {
        // 从配置文件或属性文件读取要使用的类名
        return "com.example.MyClass1";
    }
}

3、通过依赖注入调用方法

interface MyInterface {
    void myMethod();
}

class MyClass1 implements MyInterface {
    @Override
    public void myMethod() {
        System.out.println("MyClass1 implements MyInterface");
    }
}

class MyClass2 implements MyInterface {
    @Override
    public void myMethod() {
        System.out.println("MyClass2 implements MyInterface");
    }
}

@Component
class MyComponent {
    @Autowired
    private MyInterface obj;

    public void performAction() {
        obj.myMethod();
    }
}

public class Main {
    public static void main(String[] args) {
        ApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
        MyComponent component = context.getBean(MyComponent.class);
        component.performAction(); // 根据依赖注入框架的配置,调用相应的实现类
    }
}

@Configuration
@ComponentScan(basePackages = "com.example")
public class AppConfig {
    // 配置依赖注入框架
}

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐