インターフェイスは、オブジェクト指向プログラミングにおいて非常に重要な概念です。これは一連のメソッドの宣言ですが、具体的な実装はありません。swiftなどの一部のプログラミング言語は、インターフェイスを「プロトコル」として解釈しますが、これも非常に適切だと思います。インターフェイスは、メソッドの仕様のセットです。
次のインターフェイスの一般的な使用法を要約します
1.クラス内の実行プロセスの具体的な説明として
これがインターフェースの最も基本的な役割です。クラスの内部プロセスの特定のリンクが、クラス自体によって決定されない場合があります。クラスは、このステップで何が実行されるかを正確に知りません。したがって、外の世界に拡張機能を提供するために、ここでインターフェイスを設定する必要があります。
この関数の非常に良い例があります。
ストップウォッチクラス:特定のコードの実行にかかる時間を測定するために使用されます。
予備コードは次のようになります。
public class Stopwatch {
private long deltaTime;
public void clear() {
deltaTime = 0L;
}
public long getDeltaTime() {
return deltaTime;
}
public void start() {
long startTime = System.currentTimeMillis();
// do something
deltaTime = System.currentTimeMillis() - startTime;
}
}
また、Stopwatchを使用したコードは次のようになります。
public static void main(String[] args) {
Stopwatch stopwatch = new Stopwatch();
stopwatch.clear(); //时间清零
stopwatch.start(); //开始运行
System.out.printf("time: %dms\n",stopwatch.getDeltaTime());
}
次に、ストップウォッチクラス自体については、何かを実行する位置で測定するコードを決定できないことがわかります。
つまり、ここでのコードは、Stopwatch
外部でによって決定されます。したがって、ここでは、インターフェイスであるプロトコルをネゴシエートできます。Stopwatch
監視が必要なプログラムと呼ばれるインターフェイスを開くことにしました。このインターフェイスNeedMonitoringProgram
では、doProgram()メソッドが監視が必要なコードを実行します。外部での使用は、監視する必要のあるコードを定義するためのインターフェースをStopwatch
実装するだけで済みます。NeedMonitoringProgram
public interface NeedMonitoringProgram {
void doProgram();
}
オブジェクトStopwatch
に与えるNeedMonitoringProgram
public class Stopwatch {
private long deltaTime;
private NeedMonitoringProgram program;
public void setProgram(NeedMonitoringProgram program) {
this.program = program;
}
public void start() {
long startTime = System.currentTimeMillis();
program.doProgram();
deltaTime = System.currentTimeMillis() - startTime;
}
public interface NeedMonitoringProgram {
void doProgram();
}
//省略clear()和getDeltaTime()方法
}
1〜1,000,000の重ね合わせと合計を測定するために必要な時間をシミュレートします
Stopwatch stopwatch = new Stopwatch();
Stopwatch.NeedMonitoringProgram program = new Stopwatch.NeedMonitoringProgram() {
@Override
public void doProgram() {
int sum = 0;
int number = 1_000_000;
for (int i = 0; i <= number; i++) {
sum += i;
}
System.out.printf("sum: %d\n", sum);
}
};
stopwatch.setProgram(program);
stopwatch.clear();
stopwatch.start();
System.out.printf("time: %dms\n",stopwatch.getDeltaTime());
テストするコードに外部パラメーターが必要であり、外部実行結果に戻る必要があるとします。インターフェース方式も改善できます。
Param
パラメータを保存するクラスを追加します。
private Param params = new Param();
public void addParam(String key, Object value) {
params.put(key, value);
}
public interface NeedMonitoringProgram<RETURN_OBJECT> {
RETURN_OBJECT doProgram(Param params);
}
public class Param extends HashMap<String, Object> {
}
startメソッドは、オブジェクトを直接追加NeedMonitoringProgram
して、使用中のステップを減らすこともできます。またNeedMonitoringProgram
、クラスのジェネリック型は戻り型を指定します。
public <T> T start(NeedMonitoringProgram<T> program) {
long startTime = System.currentTimeMillis();
T returnObject = program.doProgram(params);
deltaTime = System.currentTimeMillis() - startTime;
return returnObject;
}
start()を実行する前に、addParam()を使用してコードに値を割り当てます。また、start()はコード実行の結果も返します。
Stopwatch stopwatch = new Stopwatch();
stopwatch.clear();
stopwatch.addParam("number", 1_000_000);
int sum = stopwatch.start(new Stopwatch.NeedMonitoringProgram<Integer>() {
@Override
public Integer doProgram(Stopwatch.Param params) {
int sum = 0;
int number = (Integer)params.get("number");
for (int i = 0; i <= number; i++) {
sum += i;
}
return sum;
}
});
System.out.printf("sum: %d\n", sum);
System.out.printf("time: %dms\n",stopwatch.getDeltaTime());
JDK8を使用すると、ラムダ式を次のように省略できます。
int sum = stopwatch.start(params -> {
int s = 0;
int number = (Integer)params.get("number");
for (int i = 0; i <= number; i++) {
s += i;
}
return s;
});
Javaには関数オブジェクトの概念はありませんが、ラムダを使用すると、関数型プログラミングの概念を完全に表現できます。ここで、インターフェイスは関数オブジェクトを表すのと同じです。
上記はインターフェースの最も基本的な機能であり、AWT、Swing、Androidなどのグラフィックプログラムで広く使用されています。制御イベントを処理するXXXListenerのようなインターフェースは、この機能を使用します。
2.ポリモーフィズム
特定のサブクラスオブジェクトは、異なるサブクラスオブジェクト間の違いを保護するための親クラスと見なすことができます。
public interface Animal {
void sayHello();
}
public class Cat implements Animal{
@Override
public void sayHello() {
System.out.println("I'm a cat.");
}
}
public class Dog implements Animal{
@Override
public void sayHello() {
System.out.println("I'm a dog.");
}
}
public static void main(String[] args) {
Animal[] animals = new Animal[]{
new Cat(), new Dog()};
for (Animal animal : animals) {
animal.sayHello();
}
}
ここでは、CatとDogがAnimal配列に均等に配置され、バッチで処理されます。ポリモーフィズムの機能は、実際には抽象クラスの機能と同じです。
3.メソッドを非表示にするために使用される特定の実装プロセス
シンプルなダオ
public interface UserDao {
User findUser(int id);
void addUser(User user);
void updateUser(User user);
void deleteUser(int id);
}
このDaoFactory
ファクトリクラスは、フレームワーク内でDaoを生成するロジックを表します(非常に単純化されています)
public class DaoFactory {
public <T> T getDaoInstance(Class<T> clazz) {
if(clazz == UserDao.class) {
return new UserDaoImpl();
} else if(……) {
}
}
}
次に、フレームワークを使用する場合、Daoのタイプを介してDaoの特定の実装オブジェクトDaoFactory
を済みます。
Daoインターフェースで使用できるメソッドのみを考慮し、Daoが追加、削除、および変更を実装する方法は考慮しません。このDaoオブジェクトを使用して、データベースの操作を完了することができます。つまり、インターフェイスは、メソッドの特定の実装をシールドし、ユーザーにとって役に立たない特定の実装クラスのいくつかのまとまりのない中間メソッドをシールドします。
4.分散サービスを公開する
public interface XXXService {
}
大規模なWebサイトプロジェクトでは、基盤となるサービスは分散展開に基づいています。たとえば、Dubboフレームワークでは、分散プロジェクトでは、インターフェイスと実装が2つのサブプロジェクトに分けられます。分散型の利点は、複数のサービスプロバイダーを設定することでサービス提供の安定性が維持されることです。すべてのサービスプロバイダーが電話を切るわけではない限り、サービスコンシューマー(コンシューマー)は安定したサービスを利用できます。サービスコンシューマーの場合、誰がサービスを提供するかは関係なく、どのサービスが利用可能かだけが関係するため、インターフェイスはメソッドの特定の実装を保護するだけでなく、さまざまなサービスプロバイダーからサービスを受け取ることもできます。ここで、インターフェースはプロトコルの役割を果たし、消費者のニーズに対応するサービスはインターフェースによって記述され、プロバイダーはインターフェースに従って独自の処理サービスロジックを実装します。
5.クラスに機能を与える
XXXableなどのいくつかのクラスに遭遇することがよくあります。
たとえばjava.io.Serializable
、これにより、クラスはシリアル化できるようになります
クラスを自分たちで強化するインターフェースや実装を作成することもできます。
WeChatペイメントを行ったことがある人は、WeChatペイメントに接続するには、xml文字列を含むHTTPリクエストを送信する必要があることを知っておく必要があります。
次に、WeChat支払い関数のクライアント(クライアント)をカプセル化できます。
次に、一般的な手順は次のとおりです。
public class WechatClient{
/**
* 统一下单
*/
public void unifiedOrder() {
//1. 生成xml
//2. 发送HTTP请求
//3. 处理请求结果
}
}
次に、クライアントクラスにHTTPリクエストを送信し、インターフェイスを宣言する機能を提供します。
public interface HttpSendable {
//发送GET请求
HttpResponse getHttps(String url);
//发送包含raw富文本的POST请求
HttpResponse postHttps(String url, String raw);
}
HttpSendable
名前が示すように、それはHTTPリクエストを送信する機能です
次に、この機能をクライアントに追加します
public class WechatClient implements HttpSendable
この機能の実装は、セカンダリコードがメインクラスのロジックを汚染することなく、抽象親クラスを使用して実装できます。
public abstract class HttpSender implements HttpSendable{
@Override
public HttpResponse getHttps(String url) {
return null;
}
@Override
public HttpResponse postHttps(String url, String raw) {
return null;
}
}
HttpSender
これはHTTPの送信者です。もちろん、HTTPを送信する機能もありHttpSendable
、クライアントはそれを継承します。
public class WechatClient extends HttpSender implements HttpSendable{
/**
* 统一下单
*/
public void unifiedOrder() {
//1. 生成xml
String xml = "";//代码略
//2. 发送HTTP请求
HttpResponse response = super.postHttps("https://", xml);
//3. 处理请求结果
//代码略
}
}
このようなコードを書くと、コードのわかりやすさが向上しますか?
6.定数インターフェイスとして
一般に、古いJavaプログラマーは、JDKの内部使用を含め、このように使用することを好みます。インターフェイスにいくつかの定数をスローします。
//申请状态常量
public interface ApplyStatusContants {
public static final String STATIC_UNTREATED = "STATIC_UNTREATED";//未处理
public static final String STATIC_ACCEPT = "STATIC_ACCEPT"; //通过
public static final String STATIC_REJECT = "STATIC_REJECT"; //拒绝
}
ただし、JDK1.5以降、列挙型が追加されています。定数インターフェイスは必要ありません。次のように実行できます。
public enum ApplyStatus {
UNTREATED, ACCEPT, REJECT
}
シンプルで粗雑。
インターフェースの使用法は依然として非常に柔軟で変更可能であり、リストされていない他の使用法があるかもしれません。それらを追加することを歓迎します。