Java 编程到接口意味着什么?

Java 编程到接口意味着什么?,java,interface,Java,Interface,我一直在大多数与编程相关的网站上听到这样的说法: 编程到一个接口,而不是一个 实施 然而,我不明白其中的含义? 举例会有所帮助 编辑:我已经收到了很多很好的答案,所以你可以用一些代码片段来补充它,以便更好地理解这个主题。谢谢 接口就像是您和接口制作人之间的合同,您的代码将执行他们的请求。此外,您希望以这样一种方式编写代码,即您的解决方案可以多次解决问题。考虑代码重用。当您对实现进行编码时,您只考虑您试图解决的问题的实例。因此,在这种影响下,您的解决方案将不那么通用,而更加集中。这将使编写遵循接口

我一直在大多数与编程相关的网站上听到这样的说法:

编程到一个接口,而不是一个 实施

然而,我不明白其中的含义?
举例会有所帮助


编辑:我已经收到了很多很好的答案,所以你可以用一些代码片段来补充它,以便更好地理解这个主题。谢谢

接口就像是您和接口制作人之间的合同,您的代码将执行他们的请求。此外,您希望以这样一种方式编写代码,即您的解决方案可以多次解决问题。考虑代码重用。当您对实现进行编码时,您只考虑您试图解决的问题的实例。因此,在这种影响下,您的解决方案将不那么通用,而更加集中。这将使编写遵循接口的通用解决方案更具挑战性。

这是一种在模块之间分离责任/依赖关系的方法。 通过定义一个特定的接口(API),您可以确保接口两侧的模块不会相互“打扰”

例如,假设模块1将负责显示特定用户的银行帐户信息,模块2将从使用的“任何”后端获取银行帐户信息

通过定义一些类型和函数以及相关参数,例如定义银行交易的结构,以及一些方法(函数),如GetLastTransactions(AccountNumber、NBTransactionWanted、ArrayToReturnTheSecrec)和GetBalance(AccountNumer),模块1将能够获得所需的信息,不用担心这些信息是如何存储或计算的。相反,Module2将只响应方法调用,按照定义的接口提供信息,但不担心在哪里显示、打印或其他任何信息

更改模块时,接口的实现可能会有所不同,但只要接口保持不变,使用API的模块最坏情况下可能需要重新编译/重建,但无论如何都不需要修改其逻辑


这就是API的概念。

本质上,接口是对互操作的一般概念的更具体的表示——它们为您可能需要“插入”的各种选项提供了规范对于一个特定的函数,也应该这样做,这样使用它们的代码就不会依赖于一个特定的选项

例如,许多数据库库充当接口,因为它们可以与许多不同的实际数据库(MSSQL、MySQL、PostgreSQL、SQLite等)一起操作,而使用数据库库的代码根本不需要更改


总的来说,它允许您创建更灵活的代码—为您的客户提供更多关于如何使用它的选项,还可能允许您在多个位置更轻松地重用代码,而不必编写新的专用代码。

这句话的核心实际上是关于依赖性的。如果我将类
Foo
编码为一个实现(
Bar
而不是
IBar
),那么
Foo
现在依赖于
Bar
。但是如果我将我的类
Foo
编码到一个接口(
IBar
而不是
Bar
),那么实现可能会有所不同,
Foo
不再依赖于特定的实现。这种方法提供了一个灵活、松散耦合的代码库,更易于重用、重构和单元测试。

通过对接口编程,您更有可能应用低耦合/高内聚原则。
通过编程到一个接口,您可以轻松地切换该接口(特定类)的实现。

您可能正在寻找类似以下内容:

public static void main(String... args) {
  // do this - declare the variable to be of type Set, which is an interface
  Set buddies = new HashSet();

  // don't do this - you declare the variable to have a fixed type
  HashSet buddies2 = new HashSet();
}
为什么第一种方式被认为是好的?假设稍后您决定需要使用不同的数据结构,例如LinkedHashSet,以便利用LinkedHashSet的功能。代码必须进行如下更改:

public static void main(String... args) {
  // do this - declare the variable to be of type Set, which is an interface
  Set buddies = new LinkedHashSet();  // <- change the constructor call

  // don't do this - you declare the variable to have a fixed type
  // this you have to change both the variable type and the constructor call
  // HashSet buddies2 = new HashSet();  // old version
  LinkedHashSet buddies2 = new LinkedHashSet();
 }
这也必须改变

public LinkedHashSet getBuddies() {
  return buddies;
}
希望您看到,即使使用这样一个小程序,您对声明变量类型也有深远的影响。由于对象来回移动如此之多,如果您仅仅依赖一个声明为接口的变量,而不是该接口的特定实现(在本例中,将其声明为集合,而不是LinkedHashSet或其他任何形式),那么它肯定有助于使程序更易于编码和维护。可以是这样的:

public Set getBuddies() {
  return buddies;
}

还有另一个好处,那就是(至少对我来说)差异帮助我更好地设计程序。但希望我的例子能给你一些想法。。。希望能有所帮助。

取一个红色2x4乐高积木,将其连接到一个蓝色2x4乐高积木上,使其中一个积木位于另一个积木之上。现在取下蓝色积木,换上黄色2x4乐高积木。请注意,即使附加块的“实现”不同,红色块也不必更改

现在去买一些其他类型的积木,它不共享乐高“界面”。尝试将其连接到红色2x4乐高上。要做到这一点,你需要改变乐高积木或其他积木,也许可以通过切割一些塑料或添加新的塑料或胶水。请注意,通过更改“实现”,您将被迫更改它或客户端


能够在不改变客户端或服务器的情况下改变实现—这就是编程到接口的意义。

这意味着您的变量、属性、参数和返回类型应该具有接口类型,而不是具体的实现

这意味着您可以使用
IEnumerable Foo(IList mylist)
而不是
ArrayList Foo(ArrayList mylist)

仅在构造对象时使用实现:

IList list = new ArrayList();
如果你这样做了
IList list = new ArrayList();
 Vector items = new Vector(); 
 // fill it 
 Object first = items.firstElement();
ArrayList items = new ArrayList();
// fill it  
Object first = items.firstElement(); // compile time error. 
 List items = new Vector();
 // fill it 
 Object first = items.get( 0 ); //
 List items = new ArrayList(); // Or LinkedList or any other who implements List
 // fill it 
 Object first = items.get( 0 ); // Doesn't break
 statement.executeOracle9iSomething();
statement.executeOracle11gSomething();
if (dataType == "XML")
{
   ... read a piece of XML data ...
}
else
{
   .. query something from the SQL database ...
}
interface IDoor
{
    void Open();
    void Close();
}

class BackwardDoor : IDoor
{
    public void Open()
    {
       // code to make the door open the "wrong way".
    }

    public void Close()
    {
       // code to make the door close properly.
    }
}

class RegularDoor : IDoor
{
    public void Open()
    {
        // code to make the door open the "proper way"
    }

    public void Close()
    {
        // code to make the door close properly.
    }
}

class RedUkTaxiDoor : BackwardDoor
{
    public Color Color
    {
        get
        {
            return Color.Red;
        }
    }
}
class DoorRepairer
{
    public void Repair(IDoor door)
    {
        door.Open();
        // Do stuff inside the car.
        door.Close();
    }
}
DoorRepairer repairer = new DoorRepairer();

repairer.Repair( new RegularDoor() );
repairer.Repair( new BackwardDoor() );
repairer.Repair( new RedUkTaxiDoor() );
class ListAdder
{
    public void PopulateWithSomething(IList list)
    {
         list.Add("one");
         list.Add("two");
    }
}

Stack stack = new Stack();
Queue queue = new Queue();

ListAdder la = new ListAdder()
la.PopulateWithSomething(stack);
la.PopulateWithSomething(queue);
class Printer
{
    public void PrintCat(Cat cat)
    {
        ...
    }

    public void PrintDog(Dog dog)
    {
        ...
    }
    ...
}
class Printer
{
    public void Print(Printable p)
    {
        Bitmap bitmap = p.GetBitmap();

        // print bitmap ...
    }
}