1. オブジェクトとクラス

今日は、典型的な Java プログラムがどのように動作するかについて少し学びます。ここで大きなニュースがあります。すべての Java プログラムはクラスとオブジェクトで構成されています。

クラスが何であるかはすでに知っていますが、オブジェクトとは何でしょうか?

たとえ話から始めます。小さな船を作りたいと想像してください。まず設計図を作成し、それを工場に渡すと、設計図に従って船が建造されます。あるいはおそらく十数個。または好きなだけ船を追加できます。単一の設計図に従って、何十隻もの同一の船が建造されます。ここが重要なことです。

Javaプログラミングでも同様です。

青写真

プログラマーはデザイナーのようなものです。デザイナーはブループリントを作成し、Java プログラマーはクラスを作成します。パーツはブループリントに基づいて作成され、オブジェクトはクラスに基づいて作成されます。

まず、クラスを作成し (ブループリントを作成し)、プログラムが実行されると、Java マシンがこれらのクラスに基づいてオブジェクトを作成します。船が設計図から作られるのと同じです。

設計図は 1 つしかありませんが、船は多数存在する可能性があります。船はそれぞれ異なり、名前も異なり、運ぶ貨物も異なります。しかし、それらは非常に似ており、すべて同じ設計を共有し、同様のタスクを実行できます。

あるいは、別の例え話もできます...

蟻塚

アリ塚は、オブジェクトがどのように相互作用するかを示す良い例です。単純な蟻塚には、女王アリ、兵士アリ、働きアリの 3 つのクラスのアリがいます。

各クラスのアリの数は異なります。アリ塚全体に対して女王アリは 1 匹ですが、兵士アリは数十匹、働きアリは数百匹います。3 つのクラスと数百のオブジェクト。アリは、厳格な規則に従って、同じクラスのアリや他のクラスのアリと相互作用します。

これはその完璧な例です。一般的なプログラムでは、すべてがこれとまったく同じです。他のすべてのクラスのオブジェクトを作成するプライマリ オブジェクトがあります。オブジェクトは相互に、またプログラムの「外の世界」と対話し始めます。オブジェクトの動作は内部的にハードコーディングされています。

これら 2 つの類似点は、同じコインの表裏の関係にあります。真実は真ん中にあります。最初の例 (設計図と船について) は、クラスとそのクラスのオブジェクトの関係を示しています。これは強力な類似点です。2 番目の例 (蟻塚に関する) は、作成されたクラスと、プログラムの実行中に存在するオブジェクトとの関係を示しています。

まずプログラム内に存在するすべてのオブジェクトのクラスを作成し、次にそれらがどのように相互作用するかを記述する必要があります。はい、その通りですが、思っているよりも簡単です。

Java では、すべてのエンティティは実行時にはオブジェクトであり、プログラムを書くということは、オブジェクトが相互作用するさまざまな方法を記述することになります。オブジェクトは単に互いのメソッドを呼び出し、必要なデータをそれらに渡します。

ドキュメンテーション

そして、メソッドに渡すデータをどうやって知るのでしょうか? あなたの前に来た人たちは、すべてを考えました。

通常、各クラスには、そのクラスが何のために作成されたかを示す説明があります。また、各パブリック メソッドには通常、そのメソッドが何を行うのか、どのデータを渡す必要があるのか​​を示す説明が含まれています。

クラスを使用するには、そのクラスが何を行うのかについての概要を理解する必要があります。そして、それぞれのメソッドが何を行うのかを正確に知る必要があります。しかし、それがどのように行われるかを知る必要はまったくありません。まるで魔法の杖のようです。

ファイルをコピーするコードを見てみましょう。

c:\\data.txt ファイルを c:\\result.txt ファイルにコピーする
package com.codegym.lesson2;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;

public class FileCopy
{
   public static void main(String[] args) throws IOException
   {
      FileInputStream fileInputStream = new FileInputStream("c:\\data.txt");
      FileOutputStream fileOutputStream = new FileOutputStream("c:\\result.txt");

      while (fileInputStream.available() > 0)
      {
         int data = fileInputStream.read();
         fileOutputStream.write(data);
      }

      fileInputStream.close();
      fileOutputStream.close();
   }
}

このコードを一行一行読んでいくと、一般的に何をするのか推測できます。ただし、それには経験と練習が必要です。しばらくすると、このコードは見慣れたものになり、理解できるようになります。


2. プログラムの設計

プログラムのデザインは総合的な芸術です。それは簡単であると同時に難しいものでもあります。シンプルな理由は、厳格な法律がないためです。禁止されていないものはすべて許可されます。まあ、そこが難しいところでもあります。何かをする方法はたくさんありますが、最適な方法を見つけるのは簡単ではありません。

プログラムの設計は本を書くのと似ています。一方では、文字、単語、文章を書くだけです。一方で、プロット、登場人物、内部矛盾、対立、ストーリーテリングのスタイル、陰謀などが重要です。

重要なのは、誰に向けてコードを書いているのかを理解することです。そして、あなたは他のプログラマのためにコードを書きます。

製品開発は必然的に変更を行うことを意味します。ここに何かが追加され、そこで何かが削除され、何かが再設計されます。こうして小さな繰り返しから、大規模で巨大なプロジェクトが生まれていくのです。

コードにとって最も重要なことは、他のプログラマが理解できるものでなければならないということです。 理解できる間違ったコードは修正できます。正しくても理解できないコードは改善できません。 できることはそれを捨てることだけです。

では、どうすれば優れたクリーンなコードを書くことができるのでしょうか?

これを行うには、次の 3 つのことが必要です。

  • メソッド内に適切でわかりやすいコードを記述する - これが最も簡単な要件です
  • どのエンティティをプログラムに含めるかを決定する
  • プログラムを論理部分に正しく分割する

これらの概念の背後にあるものは何でしょうか?

メソッド内に適切なコードを書く

基本的な英語スキルさえあれば、コードを英語の文章として読むことがいかに簡単であるかに気づいたかもしれません。

  • class Cat extends Pet— これは、Cat クラスが Pet クラスを拡張することを意味します
  • while(stream.ready())— ストリームの準備ができている限り...
  • if (a<b) return a; else return b— がaより小さい場合はbを返し、aそれ以外の場合は を返しますb

これは意図的なものです。Java は、自己文書化コード、つまりコメントなしで理解できるコードの作成を容易にするいくつかの言語のうちの 1 つです。優れた Java コードでは、多くのメソッドが英語の文章のように読み取れます。

コードを記述するときの仕事は、コードをできるだけ単純かつ簡潔にすることです。コードが読みやすいかどうかを考えるだけで、正しい方向に進み始めることができます。

Java では、読みやすいコードを書くのが一般的です。メソッドのすべてのコードが 1 つの画面 (つまり 20 ~ 30 行) に収まることが望ましいです。これは Java コミュニティ全体の標準です。コードを改善できる場合は、改善する必要があります。

良いコードの書き方を学ぶ最善の方法は、実践することです。たくさんのコードを書き、他の人のコードを研究し、経験豊富な同僚に自分のコードをレビューしてもらいます。

そして、「放っておいても大丈夫」と自分に言い聞かせた瞬間、成長は止まってしまうということを忘れないでください。

どのエンティティをプログラムに含めるかを決定する

他のプログラマーが理解できるコードを作成する必要があります。10 人中 9 人のプログラマがプログラムの設計にクラス A、B、および C を含める場合、あなたもプログラムにクラス A、B、および C を作成する必要があります。他の人が理解できるコードを作成する必要があります。

素晴らしく、動作し、高速ですが、非標準のコードは悪いコードです。

他の人のプロジェクトを研究する必要があります。これは、IT 業界で何十年にもわたって蓄積されたすべての知恵を吸収するための最良、最速、簡単な方法です。

ところで、あなたはすでに、優れた人気があり、十分に文書化されたプロジェクトであるJava SDKにアクセスできます。まずはそれから始めましょう。

クラスとその編成方法を分析します。一部のメソッドが静的であり、他のメソッドが静的でない理由を考えてください。なぜメソッドには特定のパラメータがあり、他のパラメータはないのでしょうか。これらのメソッドが正確に存在する理由、クラスの名前がどのような名前になっているのか、およびそれらが特定のパッケージに含まれているのはなぜなのか。

これらすべての質問に対する答えを理解し始めると、他の人が理解できるコードを作成できるようになります。

そうは言っても、 Java SDK のメソッド内のコードを分析しないように警告したいと思います。メソッドの多くは速度を最大化するために書き直されており、可読性には疑問があります。

プログラムを論理部分に正しく分割する

ほぼすべてのプログラムはパーツまたはモジュールに分割されています。各部分はプログラムの独自の側面を担当します。

コンピューターにはマザーボード、モニター、キーボードがあり、これらはすべて個別の疎結合部品です。さらに、USB、HDMI などの標準化された方法で通信します。キーボードにコーヒーをこぼした場合は、シンクで洗い流し、乾燥させてから使い続けることができます。

しかし、ラップトップはモノリシック アーキテクチャの一例です。個別の論理部分を識別できるように見えますが、それらははるかに統合されています。MacBookPro では、キーボードを掃除するにはラップトップの半分を分解する必要があります。そして、ラップトップにコーヒーをこぼしてしまうと、新しいラップトップを注文する理由になります。新しいコーヒーではありません。


3. 独自のクラスの作成

ただし、あなたはプログラミングを学んでいるだけなので、独自のクラスを作成する方法を学ぶことから始めるべきです。

もちろん、クラスはすでに作成されていますが、どのクラスをプログラムに含める必要があるか、どのように名前を付ける必要があるか、どのようなメソッドを持たせる必要があるかを理解する必要があります。そして、それらは互いにどのように対話すべきか。

エンティティのリスト

どこから始めればよいかわからない場合は、最初から始めてください。

初めてプログラムの設計を始めるときは、紙を手に取り、プログラム内に含める必要があるエンティティ (オブジェクト) のリストを書き留めるだけで済みます。そして、各エンティティは別個のクラスであるという原則に従ってコードを記述します。

チェス ゲームを作成したいとします。次のエンティティが必要です: チェス盤と 6 種類のチェスの駒。ピースはさまざまな方法で動き、さまざまな値を持ちます。それらが別々のクラスであることは理にかなっています。確かに、始めたばかりのときは、クラスが多ければ多いほど良いでしょう。

2 つのクラスではなく 10 つのクラスを作成する初心者プログラマーに出会うことは非常にまれです。初心者は 10 個のクラスを作成するのではなく、2 つのクラス、または場合によっては 1 つだけのクラスを作成することを好みます。プログラマーの皆さん、もっとクラスを書いてください。そして、あなたのコードはおそらくあなた以外の誰にとってもより明確になるでしょう 😛

チェス

チェスのクラスを作成することにしたとします。これらのクラスはどのようなものになるでしょうか?

チェス盤は単なる 8 × 8 配列ですか? 配列への参照を内部的に格納する別のクラスを作成することをお勧めします。その後、たとえば特定のセルが空か占有されているかを確認するなど、便利なメソッドを「chessboard」クラスに多数追加できます。

一般に、開始するときは、常に次の原則に従ってください。プログラムにはさまざまなエンティティがあり、エンティティには型があります。このタイプがクラスです。


4. 静的変数とメソッド

また、静的な変数とメソッドを使用することを忘れないでください。チェス盤上で 1 つのチェスの駒が別のチェスの駒と対話している場合、コードには、チェス盤だけでなく 1 番目と 2 番目の駒への参照を取得するメソッドが必要です。

プログラム内のどこからでもアクセスできる静的変数は、通常、「常に存在する」オブジェクトへの参照を常に渡し続けるのを避けるために使用されます。

たとえば、次のようになります。

コード ノート
public class ChessBoard
{
   public static ChessBoard board = new ChessBoard();
   public ChessItem[][] cells = new ChessItem[8][8];
   ...
}

public class Game
{
   public static void main(String[] args)
   {
      var board = ChessBoard.board;
      board.cells[0][3] = new King(Color.WHITE);
      board.cells[0][4] = new Queen(Color.WHITE);
      ...
   }
}


単一のオブジェクトへの参照ChessBoard
静的変数ではなく、8x8 の 2 次元配列。








ボードにピースを追加します。

または、静的変数の代わりに、シングルトン オブジェクトを返すメソッドを作成することもできます。たとえば、次のようになります。

public class ChessBoard
{
   private static ChessBoard board = new ChessBoard();
   public static ChessBoard getBoard()
   {
      return board;
   }

   public ChessItem[][] cells = new ChessItem[8][8];
   ...
}

public class Game
{
   public static void main(String[] args)
   {
      var board = ChessBoard.getBoard();
      board.cells[0][3] = new King(Color.WHITE);
      board.cells[0][4] = new Queen(Color.WHITE);
      ...
   }
}