1. 객체와 클래스

오늘은 일반적인 Java 프로그램이 작동하는 방식에 대해 조금 배우게 될 것입니다. 중요한 소식이 있습니다. 모든 Java 프로그램은 클래스와 객체로 구성됩니다.

클래스가 무엇인지 이미 알고 있지만 개체가 무엇입니까?

비유부터 시작하겠습니다. 작은 배를 만들고 싶다고 상상해보세요. 먼저 청사진을 만든 다음 청사진에 따라 선박이 건조될 공장에 제공해야 합니다. 또는 아마도 수십. 또는 원하는 만큼의 배. 수십 척의 동일한 선박이 하나의 청사진에 따라 건조됩니다. 그것이 여기서 중요한 것입니다.

Java 프로그래밍에서도 마찬가지입니다.

청사진

프로그래머는 디자이너와 같습니다. 디자이너는 청사진을 만들고 Java 프로그래머는 클래스를 작성합니다. 부품은 청사진을 기반으로 생성되고 개체는 클래스를 기반으로 생성됩니다.

먼저 클래스를 작성하고(청사진 만들기) 프로그램이 실행되면 Java 시스템이 이러한 클래스를 기반으로 객체를 생성합니다. 선박이 설계도에서 생성되는 것과 같은 방식입니다.

청사진은 하나뿐이지만 많은 배가 있을 수 있습니다. 배는 뚜렷합니다. 이름도 다르고 화물도 다릅니다. 그러나 그들은 매우 유사합니다. 모두 동일한 디자인을 공유하고 유사한 작업을 수행할 수 있습니다.

아니면 여기에 또 다른 비유가 있습니다 ...

개밋둑

개미집은 물체가 어떻게 상호 작용하는지에 대한 좋은 예입니다. 단순한 개미집에는 세 종류의 개미가 있습니다: 여왕개미, 병사, 일개미.

각 클래스의 개미의 수는 다릅니다. 개미집 전체에 여왕개미는 한 마리지만 병사는 수십 명, 일개미 수백 마리가 있다. 세 개의 클래스와 수백 개의 객체. 개미는 엄격한 규칙에 따라 같은 등급의 개미 및 다른 등급의 개미와 상호 작용합니다.

이것은 완벽한 예입니다. 일반적인 프로그램에서는 모든 것이 정확히 이와 같습니다. 다른 모든 클래스의 개체를 만드는 기본 개체가 있습니다. 개체는 서로 그리고 프로그램의 "외부 세계"와 상호 작용하기 시작합니다. 개체의 동작은 내부적으로 하드코딩됩니다.

이 두 비유는 동전의 양면과 같습니다. 진실은 중간에 있습니다. 첫 번째 예(청사진 및 배송 관련)는 클래스와 해당 클래스의 객체 간의 관계를 보여줍니다. 이것은 강력한 비유입니다. 두 번째 예(개미집에 관한)는 작성된 클래스와 프로그램이 실행될 때 존재하는 개체 간의 관계를 보여줍니다.

먼저 프로그램에 존재할 모든 개체에 대한 클래스를 작성한 다음 상호 작용 방식을 설명해야 합니다. 예, 맞습니다. 하지만 생각보다 쉽습니다.

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. 프로그램 설계

프로그램 디자인은 전체 예술입니다. 동시에 간단하고 어렵습니다. 엄격한 법률이 없기 때문에 간단합니다. 금지되지 않은 것은 무엇이든 허용됩니다. 음, 그리고 그것은 또한 그것을 어렵게 만드는 것입니다. 어떤 일을 하는 데는 많은 방법이 있고 가장 좋은 방법을 찾는 것은 쉽지 않습니다.

프로그램을 설계하는 것은 책을 쓰는 것과 같습니다. 한편으로는 문자, 단어 및 문장을 씁니다. 반면 줄거리, 등장인물, 내적 모순, 갈등, 스토리텔링 스타일, 음모 등이 중요하다.

가장 중요한 것은 누구를 위해 코드를 작성하는지 이해하는 것입니다. 그리고 다른 프로그래머를 위해 코드를 작성합니다 .

제품 개발은 필연적으로 변경을 의미합니다. 즉, 여기에 무언가가 추가되고, 저기에 다른 것이 제거되고, 무언가가 재설계됩니다. 그것이 작은 반복에서 크고 거대하고 거대한 프로젝트가 탄생하는 방법입니다.

코드에서 가장 중요한 것은 다른 프로그래머가 이해할 수 있어야 한다는 것입니다. 이해할 수 있는 잘못된 코드는 수정할 수 있습니다. 정확하지만 이해하기 어려운 코드는 개선할 수 없습니다.  당신이 할 수있는 일은 그것을 버리는 것뿐입니다.

그렇다면 어떻게 훌륭하고 깔끔한 코드를 작성할 수 있을까요?

이렇게 하려면 세 가지가 필요합니다.

  • 메서드 내부에 훌륭하고 이해하기 쉬운 코드 작성 — 이것이 가장 쉬운 요구 사항입니다.
  • 프로그램에 포함되어야 하는 엔터티 결정
  • 프로그램을 논리적 부분으로 올바르게 분할

이러한 개념 뒤에 무엇이 있습니까?

메서드 내에서 좋은 코드 작성

기본적인 영어 실력만 있다면 때때로 코드를 영어 문장으로 읽는 것이 얼마나 쉬운지 알아차렸을 것입니다.

  • class Cat extends Pet— 이것은 Cat 클래스가 Pet 클래스를 확장한다는 것을 의미합니다.
  • while(stream.ready())— 스트림이 준비되는 한...
  • if (a<b) return a; else return ba보다 작으면 b반환하고 a그렇지 않으면 반환합니다 b.

이것은 의도적입니다. Java는 자체 문서화 코드, 즉 주석 없이 이해할 수 있는 코드를 쉽게 작성할 수 있게 해주는 여러 언어 중 하나입니다. 좋은 Java 코드에서는 많은 메서드가 영어 문장처럼 읽힙니다.

코드를 작성할 때 귀하의 임무는 코드를 가능한 한 간단하고 간결하게 만드는 것입니다. 코드가 읽기 쉬운지 생각하고 올바른 방향으로 움직이기 시작할 것입니다.

Java에서는 읽기 쉬운 코드를 작성하는 것이 일반적입니다. 바람직하게는 메서드에 대한 모든 코드는 단일 화면(예: 20-30줄)에 맞습니다. 이것은 전체 Java 커뮤니티의 표준입니다. 코드를 개선할 수 있다면 개선해야 합니다.

좋은 코드를 작성하는 방법을 배우는 가장 좋은 방법은 연습을 통해서입니다. 코드를 많이 작성하고, 다른 사람의 코드를 연구하고, 경험이 많은 동료에게 코드 검토를 요청하세요.

그리고 당신이 스스로에게 "그냥 내버려둬"라고 말하는 순간 당신의 성장은 멈춘다는 것을 기억하세요.

프로그램에 포함되어야 하는 엔터티 결정

다른 프로그래머가 이해할 수 있는 코드를 작성해야 합니다. 10명 중 9명의 프로그래머가 프로그램 설계에 클래스 A, B, C를 포함한다면 프로그램에도 클래스 A, B, C를 만들어야 합니다. 다른 사람들이 이해할 수 있는 코드를 작성해야 합니다.

훌륭하고 작동하며 빠르지만 비표준 코드는 나쁜 코드입니다.

다른 사람의 프로젝트를 연구해야 합니다. 이것은 수십 년 동안 IT 산업에서 축적된 모든 지혜를 흡수하는 가장 좋고 빠르고 쉬운 방법입니다.

그리고 이미 훌륭하고 대중적이며 잘 문서화된 프로젝트인 Java SDK 에 액세스할 수 있습니다 . 그것으로 시작하십시오.

클래스와 구성 방법을 분석합니다. 일부 메서드는 정적이고 다른 메서드는 그렇지 않은 이유를 생각해 보십시오. 메소드에 특정 매개변수가 있지만 다른 매개변수는 없는 이유는 무엇입니까? 왜 이러한 메서드가 정확히 무엇인지, 왜 클래스 이름이 무엇인지, 특정 패키지에 포함된 이유는 무엇입니까?

이 모든 질문에 대한 답을 이해하기 시작하면 다른 사람들이 이해할 수 있는 코드를 작성할 수 있습니다.

즉, Java SDK의 메서드에서 코드를 분석하지 않도록 경고하고 싶습니다 . 많은 메서드가 속도를 최대화하기 위해 다시 작성되었으며 가독성이 의심스럽습니다.

프로그램을 논리적 부분으로 올바르게 분할

거의 모든 프로그램은 부분 또는 모듈로 나뉩니다. 각 부분은 프로그램의 고유한 측면을 담당합니다.

컴퓨터에는 마더보드, 모니터 및 키보드가 있습니다. 이들은 모두 개별적으로 느슨하게 결합된 부품입니다. 또한 USB, HDMI 등의 표준화된 방식으로 상호 작용합니다. 키보드에 커피를 쏟은 경우 싱크대에서 간단히 씻어내고 건조시킨 다음 계속 사용할 수 있습니다.

그러나 노트북은 모놀리식 아키텍처의 한 예입니다. 분리된 논리적 부분을 식별할 수 있는 것처럼 보이지만 훨씬 더 통합되어 있습니다. MacBookPro에서 키보드를 청소하려면 노트북의 절반을 분해해야 합니다. 그리고 노트북에 커피를 쏟는 것은 새 노트북을 주문하는 이유입니다. 새로운 커피가 아닙니다.


3. 나만의 수업 만들기

그러나 이제 막 프로그래밍을 배우는 중이므로 자신만의 클래스를 만드는 방법을 배움으로써 작게 시작해야 합니다.

물론 이미 클래스를 만들었지만 프로그램에 어떤 클래스를 포함해야 하는지, 이름을 어떻게 지정해야 하는지, 어떤 메서드를 가져야 하는지 이해하는 방법을 배워야 합니다. 그리고 그들이 서로 어떻게 상호 작용해야 하는지.

엔터티 목록

어디서부터 시작해야 할지 모르겠다면 처음부터 시작하세요.

처음 프로그램 설계를 시작할 때 종이 한 장을 들고 프로그램에 포함되어야 하는 개체(객체) 목록을 간단히 적을 수 있습니다. 그런 다음 각 엔터티는 별도의 클래스라는 원칙에 따라 코드를 작성합니다.

체스 게임을 작성하고 싶다고 가정해 보겠습니다. 다음 엔터티가 필요합니다: 체스판과 6가지 유형의 체스 말. 조각은 다른 방식으로 움직이고 다른 값을 갖습니다. 그들이 별도의 클래스라는 것이 이치에 맞습니다. 실제로 처음 시작할 때 수업이 많을수록 좋습니다.

2개가 아닌 10개의 클래스를 작성하는 초보 프로그래머를 만나는 것은 매우 드뭅니다. 10개의 클래스를 작성하는 대신 초보자는 두 개의 클래스 또는 아마도 하나만 작성하는 것을 좋아합니다. 그러니 동료 프로그래머 여러분, 더 많은 클래스를 작성하십시오. 그리고 당신의 코드는 아마도 당신을 제외한 모든 사람에게 더 명확해질 것입니다 😛

체스

체스를 위한 클래스를 작성하기로 결정했다고 가정해 보겠습니다. 이 클래스는 어떻게 생겼을까요?

체스판은 8 x 8 배열입니까? 배열에 대한 참조를 내부적으로 저장하는 별도의 클래스를 만드는 것이 좋습니다. 그런 다음 "chessboard" 클래스에 많은 유용한 메서드를 추가할 수 있습니다. 예를 들어 특정 셀이 비어 있는지 또는 사용 중인지 확인할 수 있습니다.

일반적으로 시작할 때 항상 이 원칙을 따라야 합니다. 프로그램에는 다양한 엔터티가 있고 엔터티에는 유형이 있습니다. 이 유형은 클래스입니다.


4. 정적 변수 및 메서드

또한 정적 변수와 메서드를 사용하는 것을 잊지 마십시오. 체스판에서 다른 체스 말과 상호 작용하는 체스 말이 있는 경우 코드에는 체스판뿐만 아니라 첫 번째 말과 두 번째 말에 대한 참조를 취하는 메서드가 필요합니다.

프로그램의 어디에서나 액세스할 수 있는 정적 변수는 일반적으로 "항상 존재하는" 개체에 대한 참조를 계속 전달하는 것을 방지하는 데 사용됩니다.

예를 들면 다음과 같습니다.

암호 메모
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);
      ...
   }
}