この記事は、MaNong.com の Sun Tenhao によって翻訳されたものです。転載については、記事の最後にある転載要件をお読みください。有料投稿プランへの参加を歓迎します。
Java 1.5 でアノテーションが導入されたとき、エンタープライズ開発者は EJB やその他のエンタープライズ製品の開発を簡素化することに大きな期待を抱いていました。同じ時期の記事「EJB 3.0 によるエンタープライズ Java 開発の簡素化」を参照してください。
しかし、それ以来、Java エンタープライズでのアノテーションの使用は、いくつかの予期せぬ結果と副作用をもたらし、その一部は今日に至るまで気付かれていません。幸いなことに、すべての副作用が無視されるわけではありません。いくつかの例を見ると、「Java アノテーションはなぜですか?」というタイトルの貴重なコメントが数多くあります。また、この記事「アノテーションは悪ですか?」も重要です。 「注釈…良いのか、悪いのか、それとも悪いのか?」
上記の議論の多くには貴重な点が含まれていますが、すべての注釈が同じというわけではありません。
アノテーションには 2 種類あり、違いは実行時にプログラムに影響を与えるかどうかです。まず、実行時のコードに影響を与えない無害なものについて説明します。もう 1 つは、実行時の動作を変更する有害なものです。無害なアノテーションには、@Deprecated、@Override、@SuppressWarnings などが含まれます。有害なアノテーションには、@Entity、@Table、@PostConstruct、@ApplicationScoped などが含まれます。
無害な注釈の中には、非常に役立つ小さな注釈セットがあります。コンパイル中にエラーをキャッチ (静的チェック) したり、安全性を保証したりするものもあります。便利なアノテーションには、@Override、(Checker Framework) の @NonNull/@Nullable などがあります。
いくつかの有害なアノテーションを定義しましたが、なぜそれらの使用を避けなければならないのでしょうか?
@PostConstruct メソッドを持つ標準の Java Data クラスを想像してください。このアノテーションは、オブジェクトの作成後にアノテーション付きメソッドを呼び出す必要があることを示します。この機能は JVM では処理されないため、Date クラスは意味的には何もせずに暗黙的に未知のフレームとコンテナを取得します。このコードがどのコンテナーでも実行されず、JVM でのみ実行される場合はどうなるでしょうか?このアノテーションにより、このクラスの再利用性が大幅に低下します。さらに、Date を使用する単体テストは悪夢になります。ポスト構築が毎回正しくバインドされていることを確認する必要があり、互換性のあるコンテナーをシミュレートする必要があるからです。これは少しばかげています。Date クラスを実行するにはコンテナーが必要ですが、これは実際、クラス、メソッド、パラメーターに対するアノテーションの悪影響です。
ビジネス ロジックが複雑な場合が多く、単純な Date クラスよりも多くの依存関係や関係が必要になることは否定できません。ただし、有害なアノテーションは、依存関係と制約だけであり、明示的または暗黙的にクラスに追加する理由はありません。
残念ながら、Java Enterprise 5 では有害な主張が大規模に正当化されています。エンタープライズ API の初期の使いやすさの問題を修正するために、アノテーションを使用してシステムの冗長で使いにくい部分を非表示にしました。新しい JEE 5 は「軽量」「シンプル」と評価されており、表面的にはそのように見えます。しかし、小さいながらも重大な誤用が広まりました。
@Stateless public class DocumentRepository { public Document getDocument(String title) { ... } ... }
ステートレス EJB を取得したい場合は、クラスで @Stateless アノテーションを宣言するだけです。実際、このクラスの作成には数回クリックするだけで済みますが、このクラスの有害なアノテーションは数百ページのドキュメントに関連付けられており、メガバイトのアプリケーション サーバー上でのみ実行されることに注意してください。これをどうして「軽い」と言えるのでしょうか?したがって、このアノテーションは、実際に記述する必要がある Java コードの単なるプレースホルダーであり、コードは依然として何らかの形式で存在する必要があります。今は注釈の下に隠れているだけです。
残念ながら、この回避策はパターンとして知られており、現在、有害なアノテーションが JPA、CDI、Common Annotations、JAXB などに広く配布されています。
アノテーションは開発環境としてよく使用されるため、有害なアノテーションが単一責任原則または懸念事項の分離のベスト プラクティスとして使用されることがあります。
次の CDI の例を考えてみましょう:
@ApplicationScoped public class DocumentFormatter { ... }
上記のアノテーションは、このクラスが CDI Bean である必要があることを説明しています。これは、このクラスが CDI によってのみインスタンス化され、各アプリケーションにインスタンスが 1 つだけ存在することを意味します。
この情報はこのカテゴリに属しません。このサービスは、現在のアプリケーションでの役割に (いかなる形でも) 機能的な影響を与えません。ここには明らかな懸念が 2 つあります。
JPA の簡単な例:
@Entity @Table("PERSON") public class Person { ... }
问题在于这种类往往是”领域对象(domain objects)”,它们直接将领域模型持久化。更糟的是,数据传送对象(DTO)用来在对象之间传送数据,使得整个构造变得脆弱,因为对象间耦合过于紧密。不管怎样,这是一种错误的方式。
所有的这些附加的功能和(或)信息应该从这些类中分离出来,但是它们却悄悄混在一起,因为它们”只不过”是注解。
注解有时会传染其他对象。回顾上面那个CDI Bean。每个使用它的对象,每个依赖它的对象现在都拥有一个CDI注解,否则依赖关系树就不会构建成功。
@Entity注解也一样。因为对象之间的关系,其他对象也通过注解持久化,很快所有的持久化对象都会有这个注解。我们无法使用原生的第三方对象(除非序列化或包装它们),我们无法使用其他持久化机制(比如用NoSQL DB存放对象)。
这些注解使得这些对象无法复用。它们只能在一个严格的、受控制的、不透明的环境中使用,不能和任何东西整合。
是XML吗?当然不是,至少对于上面的例子来说不是。
Spring框架使用配置来管理对象,因此可以用XML当做配置文件。然而,是否某个依赖需要在运行期改变,而不通过重新编译?如果不需要,那么很难说配置应该用另一门语言来表示,尤其重构困难、测试困难、管理需要特殊工具。
真正的替代品当然是好的Java代码,正确封装并解耦的。是的,用代码来管理对象,尽管有时被当做样板(boilerplate),但并不算糟糕。它带来一些好处,比如让代码可读、可调试、可重构。只有那些长片的、复杂的、冗余的样板是糟糕的,比如“关于EJB 2.0”。但是解决方案并不是摆脱所有的样板或用另一种语言隐藏样板,而是简单干净的架构,直接而不多余的信息,简单并合适的方式来面向对象。
这也适用于JPA、Spring和其他东西。误用注解来表示功能会发生Stcakoverflow上这个问题“Arguments Against Annotations”,为什么不用已有的工具呢:比如Java语言本身和编译器,来解决这类问题,面向对象和软件最佳实践。
如果注解在代码运行期加上了额外功能和约束,那它是有害的。这很糟糕,因为它隐藏了类或方法的切面,使之难懂、难复用、难重构、难测试。
不幸的是Java Enterprise不理睬Java开发者社区中发对注解的声音。所以企业级Java和其他”官方”框架更不可能重视这类问题。
至少我们可以持续关注有害的注解,如果可能尽量避免使用,编写新的框架和软件替换掉注解,不会出现有害注解所带来的问题。
以上就是Java中万恶的注解 的内容,更多相关内容请关注PHP中文网(www.php.cn)!