scone-lemon

[디버깅 과목평가 대비] JAVA WORKSHOP 6 (다형성 & 제어자) (추상클래스, 인터페이스, 싱글톤패턴 내용정리) 본문

ETC./싸피 이모저모 (2021~2022)

[디버깅 과목평가 대비] JAVA WORKSHOP 6 (다형성 & 제어자) (추상클래스, 인터페이스, 싱글톤패턴 내용정리)

lemon-scone 2021. 8. 22. 15:22

Book.java

 

워크샵 5와 같다.

 

package workshop.java06;

public class Book {

	String isbn;
	String title;
	String author;
	String publisher;
	int price;
	String desc;
	
	public Book() {
		super();
	}

	public Book(String isbn, String title, String author, String publisher, int price, String desc) {
		super();
		this.isbn = isbn;
		this.title = title;
		this.author = author;
		this.publisher = publisher;
		this.price = price;
		this.desc = desc;
	}

	public String getIsbn() {
		return isbn;
	}

	public void setIsbn(String isbn) {
		this.isbn = isbn;
	}

	public String getTitle() {
		return title;
	}

	public void setTitle(String title) {
		this.title = title;
	}

	public String getAuthor() {
		return author;
	}

	public void setAuthor(String author) {
		this.author = author;
	}

	public String getPublisher() {
		return publisher;
	}

	public void setPublisher(String publisher) {
		this.publisher = publisher;
	}

	public int getPrice() {
		return price;
	}

	public void setPrice(int price) {
		this.price = price;
	}

	public String getDesc() {
		return desc;
	}

	public void setDesc(String desc) {
		this.desc = desc;
	}
	
	@Override
	public String toString() {
		return isbn + " | " + title + " | " + author + " | " + publisher  + " | " + price  + " | " + desc;
	}
	
}

 

 

Magazine.java

 

워크샵 5와 같다.

 

package workshop.java06;

public class Magazine extends Book {

	private int year;
	private int month;
	
	public Magazine(String isbn, String title, String author, String publisher, int price, String desc, int year, int month) {
		super(isbn, title, author, publisher, price, desc); // super()
		this.year = year;
		this.month = month;
	}

	public int getYear() {
		return year;
	}

	public void setYear(int year) {
		this.year = year;
	}

	public int getMonth() {
		return month;
	}

	public void setMonth(int month) {
		this.month = month;
	}
	
	@Override
	public String toString() {
		return super.toString() + "|" + year + "|" + month; // super.toString()
	}
}

 

 

IBookManager.java

 

인터페이스를 구현하는데는 어려움이 없었다. 단순히 명세표에 나와있는 데로 메소드만 적어주면 되기 때문에!

주의해야 할 점은 인터페이스에서 메소드에 대한 제한자 선언이라고 생각한다.

또한 추상클래스와 인터페이스의 차이점을 명확하게 하고 가는 것이라고 생각한다.

 

더보기

추상클래스

추상 클래스의 구현과 목적

 

ex1. 

class Shape { }

class Line extends Shape { }

class Rect extends Shape { }

class Circle extends Shape { }

Line, Rect, Circle이 Shape를 상속받는 상황이고, Shape는 void draw() 메소드를 가지고있다.

 

ex2.

abstract class Shape { }

class Line extends Shape { }

class Rect extends Shape { }

class Circle extends Shape { }

Line, Rect, Circle이 Shape를 상속받는 상황이고, Shape는 abstact void draw() 메소드를 가지고있다.

 

ex1의 상황일 때 Line, Rect, Circle은 draw()를 오버라이딩 하지 않아도 무관하다.

그러나 ex2의 상황일 때는 조금 다르다.

Shape의 draw() 메소드가 추상 메소드이기 때문에 이를 상속받는 Line, Rect, Circle은 반드시 draw()를 오버라이딩 해야한다. 오버라이딩 하지 않거나 이름을 잘못 작성한다면 컴파일 오류가 발생한다.

 

추상 클래스는 추상 메소드를 통해 서브 클래스가 구현할 메소드를 명료하게 알려주는 인터페이스의 역할을 하고, 서브 클래스는 추상 메소드를 목적에 맞게 구현하는 다형성을 실현할 수 있다.

 

추상 클래스의 용도

 

개발자들은 서브 클래스에서 추상 클래스에 선언된 추상 메소드를 모두 구현해야 한다. 추상 클래스를 책의 목차에 비유한다면, 서브 클래스는 목차에 따라 작성된 책과 같다. 

추상 클래스를 이용하면 응용 프로그램의 설계와 구현을 분리할 수 있다. 또한 추상 클래스로 기본 방향을 잡아놓고 서브 클래스에서 구현하면 구현 작업이 쉬워진다. 또한 추상 클래스는 계층적 상속 관계를 가지는 클래스들의 구조를 만들 때 적합하다.

추상 클래스를 상속하는 서브 클래스 구현에 있어서 강제성을 부여한다.

 

 

인터페이스

 

사용방법

 

1. 인터페이스는 객체를 생성할 수 없다. (인터페이스에는 구현되지 않은 추상 메소드를 가지고 있기 때문에)

2. 인터페이스 타입의 레퍼런스 변수는 선언 가능하다.

3. 인터페이스끼리 상속된다.

4 인터페이스를 상속받아 클래스를 작성하면 인터페이스의 모든 추상메소드를 구현하여야 한다.

5. 인터페이스끼리 다중상속이 가능하다. (interface 인터페이스 extends 인터페이스1, 인터페이스2)

 

인터페이스의 목적

 

스펙을 주어 클래스들이 그 기능을 서로 다르게 구현할 수 있도록 하는 클래스의 규격 선언이며, 클래스의 다형성을 실현하는 도구이다.

 

 

추상 클래스 vs 인터페이스

 

추상 클래스의 목적과 구성

 

추상 클래스는 서브 클래스에서 필요로 하는 대부분의 기능을 구현하여 두고 서브 클래스가 상속받아 활용할 수 있도록 하되, 서브 클래스에서 구현할 수밖에 없는 기능만을 추상 메소드로 선언하여, 서브 클래스에서 구현하도록 하는 목적(다형성)을 가진다.

추상 메소드와 일반 메소드 모두 포함하며, 상수와 변수 필드 모두 포함한다.

 

인터페이스의 목적과 구성

 

인터페이스는 객체의 기능을 모두 공개한 표준화 문서와 같은 것으로, 개발자에게 인터페이스를 상속받는 클래스의 목적에 따라 인터페이스의 모든 추상 메소드를 만들도록 하는 목적(다형성)을 가진다.

변수 필드(멤버 변수)는 포함하지 않는다.

상수, 추상 메소드, 일반 메소드, default 메소드, static 메소드 모두 포함한다.

protected 접근 지정 선언이 불가하고, 다중 상속을 지원한다.

 

 

- 생능출판, 명품자바 참고하여 작성함

- https://hyonee.tistory.com/145 참고하여 작성함

 

package workshop.java06;

public interface IBookManager {

	public void add(Book book);
	public void remove(String isbn);
	public Book[] getList();
	public Book searchByIsbn(String isbn);
	public Book[] searchByTitle(String title);
	public Magazine[] getMagazines();
	public Book[] getBooks();
	public int getTotalPrice();
	public double getPriceAvg();
	
}

 

 

BookManagerImpl.java

 

메소드 구현은 이전 워크숍과 같았기 때문에 어려운 점은 없었지만, 싱글톤 패턴으로 생성자를 선언하는 데에서 막혔다.

싱글톤 패턴은 생성자를 private로 만듦으로써 아무데서나 객체를 new 로써 생성하지 않기 위함이고, 대신에 instance를 getInstance 함수로 리턴해 주는 패턴이라고 막연하게? 알고 있었다.

이 기회로 싱글톤 패턴을 짚고 넘어가야 할 것 같다.

 

더보기

싱글톤 패턴

 

싱글톤 패턴 사용이유와 문제점

https://jeong-pro.tistory.com/86

 

싱글톤 패턴 선언 방법

https://coding-factory.tistory.com/709

https://thisisnew-storage.tistory.com/8

 

싱글톤 패턴에 세가지나 있다니...

모르겠고 그냥 기본 싱글톤 패턴 외워서 내일 시험봐야지 ㅠㅠ

 

package workshop.java06;

import java.util.Arrays;

public class BookManagerImpl implements IBookManager {
	
	// 싱글톤 패턴
	// 생성자, instance 는 private
	// getInstance 만 public
	/*private BookManagerImpl() { } 
	private static BookManagerImpl instance = new BookManagerImpl();
	public static BookManagerImpl getInstance() { return instance; }*/
	private BookManagerImpl() { } 
	private static IBookManager instance = new BookManagerImpl();
	public static IBookManager getInstance() { return instance; }
	
	int MAX_SIZE = 100;
	int size = 0;
	Book[] books = new Book[MAX_SIZE];
		
	@Override
	public void add(Book book) {
		if(size<MAX_SIZE) {
			books[size++] = book;
		}
	}
	
	@Override
	public void remove(String isbn) {
		for (int i = 0; i < size; i++) {
			if(books[i].getIsbn().equals(isbn)) {
				books[i] = books[size-1];
				books[size-1] = null;
				size--;
				break;
			}
		}
	}
	
	@Override
	public Book[] getList() {
		return Arrays.copyOfRange(books, 0, size);
	}
	
	@Override
	public Book searchByIsbn(String isbn) {
		for (int i = 0; i < size; i++) {
			if (books[i].getIsbn().equals(isbn)) {
				return books[i];
			}
		}
		return null;
	}
	
	@Override
	public Book[] searchByTitle(String title) {
		int cnt = 0;
		for (int i = 0; i < size; i++) {
			if (books[i].getTitle().contains(title)) {
				cnt++;
			}
		}
		int idx = 0;
		Book[] temp = new Book[cnt];
		for (int i = 0; i < size; i++) {
			if (books[i].getTitle().contains(title)) {
				temp[idx] = books[i];
				idx++;
			}
		}
		return temp;
	}
	
	@Override
	public Magazine[] getMagazines() {
		int cnt = 0;
		for (int i = 0; i < size; i++) {
			if (books[i] instanceof Magazine) {
				cnt++;
			}
		}
		int idx = 0;
		Magazine[] temp = new Magazine[cnt];
		for (int i = 0; i < size; i++) {
			if (books[i] instanceof Magazine) {
				temp[idx] = (Magazine) books[i]; // Magazine
				idx++;
			}
		}
		return temp;
	}
	
	@Override
	public Book[] getBooks() {
		int cnt = 0;
		for (int i = 0; i < size; i++) {
			if (!(books[i] instanceof Magazine)) {
				cnt++;
			}
		}
		int idx = 0;
		Book[] temp = new Book[cnt];
		for (int i = 0; i < size; i++) {
			if (!(books[i] instanceof Magazine)) {
				temp[idx] = books[i];
				idx++;
			}
		}
		return temp;
	}
	
	@Override
	public int getTotalPrice() {
		int total = 0;
		for (int i = 0; i < size; i++) {
			total =  total + books[i].getPrice();
		}
		return total;
	}
	
	@Override
	public double getPriceAvg() {
		return getTotalPrice()/size;
	}
	
}

 

 

BookTest.java

 

BookTest를 구현하는데는 크게 어려움이 없었다.

다만 싱글톤 패턴으로 인해 BookManagerImpl를 new로 객체생성할 수 없어서, 싱글톤 패턴일 때는 어떻게 객체의 생성자를 초기화하더라? 아니 생성자가 private 니까 안될것 같고 어떻게 getInstance를 선언하더라? 고민하다가 결국 솔루션을 참고했다.

IBookManager bm = BookManagerImpl.getInstance(); 이 부분에서 왜 왼쪽은 인터페이스 객체를 사용하는지 잘 모르겠다.

 

package workshop.java06;

public class BookTest {
	
	public static void main(String[] args) {
		
		IBookManager bm = BookManagerImpl.getInstance();
		
		bm.add(new Book("21424", "Java Pro", "김하나", "jaen.kr", 15000, "Java 기본 문법"));
		bm.add(new Book("21425", "Java Pro2", "김하나", "jaen.kr", 25000, "Java 응용"));
		bm.add(new Book("35355", "분석설계","소나무","jaen.kr",30000,"SW 모델링"));
		bm.add(new Magazine("45678", "월간 알고리즘", "홍길동", "jaen.kr", 10000, "1월 알고리즘", 2021, 1));
		
		System.out.println("\n1. 도서 전체 목록");
		for (Book book : bm.getList()) {
			System.out.println(book);
		}
		
		System.out.println("\n2. 일반 도서 목록");
		for (Book book : bm.getBooks()) {
			System.out.println(book);
		}
		
		System.out.println("\n3. 잡지 목록");
		for (Book book : bm.getMagazines()) {
			System.out.println(book);
		}
		
		System.out.println("\n4. 도서 제목 포함검색 : Java");
		for (Book book : bm.searchByTitle("Java")) {
			System.out.println(book);
		}
		
		System.out.println("\n5. 도서 가격 총합 : " + bm.getTotalPrice());
		
		System.out.println("\n6. 도서 가격 평균 : " + bm.getPriceAvg());
		
	}
}