漫谈Java措施设计中的接口应用
副标题#e#
Java语言提供了一种接口(interface)机制。这种接口机制使Java的面向工具编程变得越发机动。我们可以用接口来界说一个类的表示形式,但接口不能包括任何实现。在《Thinking in Java》一书中,作者对接口有这样的描写:“接口(interface)比抽象(abstract)的观念更进了一步。你可以把一个接口当作是一个纯的抽象类。”我认为作者对接口的这一表明再精确不外了。
领略并用好接口机制将辅佐我们更好的把握Java这种面向工具的编程语言。下面我们来接头一下接口的利用法则以及相关的应用。
一、接口的界说及实现
界说接口和界说类相似,只是要把 class要害字换为 interface。界说要领时只需要要领名,返回范例和参数列表,不能有要领体。接口中可以界说字段,这些字段都被暗指为 static 和 final,因此应该按照需要先定好这些字段的值。譬喻:
public interface Flyable {
void fly();
}
public interface Talkable {
void talk();
}
public interface Message {
int MAX_SIZE = 4096;
String getMessage();
}
上面界说的几个接口中,Flyable 和 Talkable 只界说了一个要领,而 Message 里除了要领外尚有一个字段 MAX_SIZE。可以看出这些接口只界说了类的表示形式,而不包括任何实现,所以不能直接利用。要利用这些接口就需要有相应的类去实现它们。实现接口时应该先在类名后用 implements 要害字申明将要实现的接口,假如要实现多个接口,应该用逗号将它们离隔,然后一一实现这些接口中界说的要领。如下面的例子:
public class Parrot implements Flyable, Talkable {
public void fly() {
System.out.println("Flying like a parrot…");
}
public void talk() {
System.out.println("Hello! I am a parrot!");
}
}
public class TextMessage implements Message {
String message;
public void setMessage(String msg) {
message = msg;
if (message.length() > MAX_SIZE)
message = message.substring(0, MAX_SIZE);
}
public String getMessage() {
return message;
}
}
在 Parrot(鹦鹉)例子中,我们用接口 Flyable 来暗示航行本领,Talkable 暗示措辞本领,但它们并不包括详细实现。而 Parrot 同时具有这两种本领,所以我们为 Parrot 类同时实现了 Flyable 和 Talkable 这两个接口。同样我们还可以界说一个Swallow(燕子)类,但燕子只有航行本领,所以我们只需要为 Swallow 实现 Flyable 就行了。因为它们各自的的航行要领有所差异,所以它们有各自关于航行的详细实现。
别的,正因为一个类可以同时实现多个接口,使得Java的面向工具特性变得很是机动。运用这种特性,我们可以实现雷同C++语言中多担任那样的特性,甚至更机动的一些特性。下面我们来接头一下接口在实际中的应用。
二、用接口来界说一些全局变量
因为接口内的字段都是static和final的,所以我们可以很利便的操作这一点来建设一些常量。譬喻:
public interface Constants {
String ROOT = "/root";
int MAX_COUNT = 200;
int MIN_COUNT = 100;
}
在利用时可以直接用Constants.ROOT这样的形式来引用个中的常量。我们还可以用下面这种要领来建设初始值不确定的常量。
public interface RandomColor {
int red = Math.random() * 255;
int green = Math.random() * 255;
int blue = Math.random() * 255;
}
个中red、green和blue的值会在第一次被会见时成立,然后保持稳定。
#p#副标题#e#
三、用接口来界说根基数据布局
在设计一套软件系统的初期,我们可以用接口来对一些根基数据元素的特性来举办一些描写,再按照需要举办差异的实现。请各人看看下面这个例子:
public interface User {
int getAge();
String getName();
String getPassword();
}
public class XMLUser implements User {
// 这里用XML技能实现User接口中的要领
public int getAge() { ... }
public String getName() { ... }
public String getPassword() { ... }
}
public abstract class UserFactory {
public static UserFactory getUserFactory() {
return new XMLUserFactory();
}
public User getUser(String name);
public User getAdmin();
public User createUser(String name, String password, int age);
public void addUser(User user);
public void delUser(User user);
}
public class XMLUserFactory extends UserFactory {
// 这里用XML技能实现的UserFactory的抽象要领
}
#p#分页标题#e#
在这个例子中,我们界说了一个接口User和一个抽象类UserFactory。然后我们用XML技能实现这两个类。可以看出,我们只需要从用UserFactory的getUserFactory()就可以获得一个UserFactory的实例,而不消去思量这个实例的详细实现要领。通过UserFactory的这个实例我们还可以直接获得User的实例,也不消去考详细的实现要领。
假如我们抉择用JDBC技能来实现User和UserFactory,我们只需要按上面的形式实现JDBCUser和JDBCUserFactory就行了。然后把UserFactory中的getUserFactory要领修改一下就可以改变了它们的实现要领。而我们已经写好的挪用UserFactory和User的部门不需要做任何修改。
这是用接口来界说数据布局的一个简朴的例子,在实际应用中尚有许多机动的利用要领,各人需要在进修进程中不绝的去体会。
四、领略漫衍式应用的道理
今朝有许多软件项目都利用了漫衍式的技能。Java 有多种支持漫衍式应用的技能,早期用的较量多的有 RMI、CORBA 等技能,而此刻 EJB 技能更为风行一些。但这些技能不管怎么成长,其实都是以接口为基本的。
以长途要领挪用 RMI(Remote Method Invocation)为例。在编写 RMI 应用时,我们需要做两件最根基的事,首先要界说一个接口,这个接口要担任 java.rmi.Remote 接口,这个接口中应该包括你要从远端挪用的要领名。接下来就是写一个类来实现这个接口中的要领。譬喻:
public interface Product extends java.rmi.Remote {
String getName() throws java.rmi.RemoteException;
}
public class ProductImpl implements Product {
String name;
public ProductImpl(String n) {
name = n;
}
public String getName() throws java.rmi.RemoteException {
return name;
}
}
在这个例子中,接口 Product 是放在客户端的,而 ProductImpl 是放在处事器端的,客户在利用时只需要用指定的法则获得Product 的实例就行了,不消去思量 Product 接口里的要领是如何实现的。在界说好这两个类后,用Java开拓包呼吁“rmic ProductImpl”就可以辅佐我们自动生成两个类 ProductImpl_Skel 和 ProductImpl_Stub。这两个类就包括了RMI挪用的运作机制。有乐趣的伴侣可以把这两个类反编译后研究一下。你会发明个中 ProductImpl_Stub 实际上是接口 Product 的一个实现类。RMI 机制就是用这个类来生成 Product 的实例供客户端利用。另一个类 ProductImpl_Skel 则是在处事端响应 ProductImpl_Stub 的挪用请求的类。而 RMI 最底层的通讯道理则是操作 ObjectInputStream 和 ObjetOutputStream 通过 Socket 将要挪用的要领名及参数列表传随处事器端,处事器端再通过特定的要领挪用实现类(在本例中是 ProductImpl)的对应要领,然后将功效通过 Socket 传回客户端就行了。由于 Skel 和 Stub 类是用东西生成的,所以就大大节减了开拓的时间。别的,假如我们需要修改一些实现要领或错误,只需要对处事器端的实现类举办修改就可以了,也就是说这种漫衍式应用的大部门维护事情在处事器端就可以完成。
此刻越来越多的应用利用了 EJB 这种技能。EJB 是从 RMI 成长而来的一项技能,它比RMI界说得越发完善,可以得到更好的面向工具的特性。但它的法则要比RMI巨大一些。可是不管它多巨大,它同样是利用了接口来界说各类差异的 Bean,也同样需要编写相应的实现类来完成详细的成果,最后还要通过 Socket 来举办通讯。EJB的运作机制自己有必然的巨大性,所以其应用的效率理所虽然就会受到必然的影响。因此在选择开拓技能时应该按照应用的局限和特点仔细思量,不必然风行的技能就必然能适应你的应用。假如你很好的把握了面向工具的设计原则,你就可以自行设计。也许你可以按照本身应用的特点设计出更符合的漫衍式应用布局。
五、结论
除了上述的一些应用外,尚有许多处所可以利用接口,好比在Java的事件机制中就常用到接口。别的,对付一些已经开拓好的系统,在布局长举办较大的调解已经不太现实,这时可以通过界说一些接口并追加相应的实现来完乐成能布局的扩展。
总之,学好接口可以辅佐我们更好的领略和运用面向工具的设计原则。使我们能设计出更好的软件系统。由于本人程度的限制,如有错误之处还请多多指正。