Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Java Assignment3 upload by HyunsooJung #21

Open
wants to merge 11 commits into
base: main
Choose a base branch
from
15 changes: 15 additions & 0 deletions me/day05/practice/ArrayUtil.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package me.day05.practice;

import java.util.List;

public class ArrayUtil {

static <T> T[] listToArray(List<T> list) {
T[] resultArray = (T[]) new Object[list.size()];

for (int i = 0; i < resultArray.length; i++)
resultArray[i] = list.get(i);

return resultArray;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

이 메서드는 사용되는 코드인가요?
사용되지 않는 코드는 지워주세요.

}
}
109 changes: 109 additions & 0 deletions me/day05/practice/Electronic.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
package me.day05.practice;

import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.Arrays;
import java.util.Objects;

public class Electronic {

enum CompanyName { SAMSUNG, LG, APPLE }
enum AuthMethod { FINGERPRINT, PIN, PATTERN, FACE }

private static final int MAX_REGISTRATION_NUMBER = 9999;

private static int registrationNo;

private String productNo;
private String modelName;
private CompanyName companyName;
private String dateOfMade;
private AuthMethod[] authMethod;

Electronic () {
registrationNo++;
setDateOfMade();
setProductNo();
}

Electronic (String modelName, CompanyName companyName, AuthMethod[] authMethod) {
this();
this.modelName = modelName;
this.companyName = companyName;
this.authMethod = authMethod;
}

private void setDateOfMade(){
DateTimeFormatter timeFormatter = DateTimeFormatter.ofPattern("yyMMdd");
dateOfMade = timeFormatter.format(LocalDate.now());
}

private void setProductNo(){
if (registrationNo >= MAX_REGISTRATION_NUMBER) resetRegistrationNo();
productNo = dateOfMade + String.format("%4d", registrationNo).replace(" ", "0");
}

private void resetRegistrationNo(){
registrationNo = 1;
}

public boolean isContainAuthMethod(AuthMethod authMethod){
for (AuthMethod auth : this.authMethod)
if (authMethod.equals(auth)) return true;
return false;
}
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

이 부분은 요구사항에는 없었지만
Electronics클래스의 groupByAuthMethod()를 구현하다가
있었으면 좋겠다는 느낌이 들어 추가했습니다.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

굳굳!!
근데 is contain이 문법적으로 맞나요?

꼭 단어나 문법이 정확하진 않아도 되지만 가급적이면 지켜주는게 좋아요.
map의 containsKey가 있으니 저라면 'contains~'로 지었을거 같네요.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

헉! 지금까지 계속 contain으로 사용하고 있었네요 맙소사,, 감사합니다


public String getProductNo() {
return productNo;
}

public String getModelName() {
return modelName;
}

public void setModelName(String modelName) {
this.modelName = modelName;
}

public CompanyName getCompanyName() {
return companyName;
}

public void setCompanyName(CompanyName companyName) {
this.companyName = companyName;
}

public String getDateOfMade() {
return dateOfMade;
}

public AuthMethod[] getAuthMethod() {
return authMethod;
}

public void setAuthMethod(AuthMethod[] authMethod) {
this.authMethod = authMethod;
}

@Override
public int hashCode() {
return Objects.hash(productNo, modelName, companyName, dateOfMade, Arrays.hashCode(authMethod));
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

꼭 모든 프로퍼티가 아니라 특정 몇개의 프로퍼티로 hashCode를 만들기도 하죠. 좋은 아이디어네요.
다만 hashCode는 속도 비교가 아니라 registrationNo가 Electoronic의 해시값이 될 수 있도록 골고루 분산되어 있을까를 더 고민해야합니다.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

이 부분은 한번 찾아보고, 고민해 보겠습니다


@Override
public boolean equals(Object obj) {
if (this == obj) return true;
if (obj == null || getClass() != obj.getClass()) return false;
return Objects.equals(productNo, ((Electronic)obj).productNo);
}

@Override
public String toString() {
return "Electronic { " +
"productNo=" + productNo +
", modelName=" + modelName +
", companyName= " + companyName +
", dateOfMade=" + dateOfMade +
", authMethod=" + Arrays.toString(authMethod) + " }";
}
}
15 changes: 15 additions & 0 deletions me/day05/practice/ElectronicArrayUtil.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package me.day05.practice;

import java.util.List;

public class ElectronicArrayUtil {

static Electronic[] listToArray(List<Electronic> list) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

이 메서드가 분리된 유틸 클래스에 있는 것과 Electronic에 있는 것, 어떤 차이가 있을까요?
왜 분리하고 싶었는지가 궁금합니다!!

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Users 에서도 groupBy 기능이 생길 것 같아서
추후 확장을 위해 제네릭으로 선언하고 싶었습니다.

제네릭으로 해당 유틸 로직을 만드는 데 실패해서 임시방편으로 Electronic 클래스를 위한 유틸클래스로 분리했습니다

Electronic[] resultArray = new Electronic[list.size()];

for (int i = 0; i < resultArray.length; i++)
resultArray[i] = list.get(i);

return resultArray;
}
}
140 changes: 140 additions & 0 deletions me/day05/practice/Electronics.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
package me.day05.practice;

import me.day05.practice.Electronic.AuthMethod;
import me.day05.practice.Electronic.CompanyName;

import java.util.*;

public class Electronics {

private static final int DEFAULT_CAPACITY = 10; // Default initial capacity
private static final Electronic[] EMPTY_ELECTRONIC_LIST = {};

private static Electronic[] electronicList;
private static Electronics electronicsInstance;

private int size;
private int capacity;

Electronics(){
electronicList = EMPTY_ELECTRONIC_LIST;
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

싱글톤으로 사용하고자 한다면 생성자는 private으로 막아주는 것이 일반적입니다.
ELECTRONIC_LIST가 비어있기 때문에 상관없다고 생각할 수 있으나 당장 생성에는 문제가 없어서 이 코드를 사용하는 다른 개발자에게 혼란을 주기 쉽거든요.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

헉 너무 기본적인 실수,, 열번 백번 더 확인하겠습니다,,!


// TODO: 1. Electronics 클래스의 객체를 싱글톤으로 생성하는 함수를 작성하시오.
public static Electronics getInstance() {
if (electronicsInstance == null) electronicsInstance = new Electronics();
return electronicsInstance;
}

// TODO: 2. 전자제품 일련번호 productNo를 통해 인자로 주어진 일련번호에 해당하는 전자제품을 반환하는 함수를 작성하시오.
public Optional<Electronic> findByProductNo(String productNo){
for (Electronic electronic : electronicList)
if (productNo.equals(electronic.getProductNo()))
return Optional.of(electronic);

return Optional.empty();
}
Comment on lines +29 to +35
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

equals() 메소드를 사용할 때 모종의 상황 발생으로
electronicNull일 경우 NPE가 발생할 수 있다고 생각하였습니다.

다시 생각해보니 productNo도 인자 값을 Null으로 넘기는 경우에 NPE가 발생하는데
널 참조 방지 코드를 추가하는 게 좋을까요?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

이정도면 충분할 것 같습니다. (사실 해도 됩니다. null 체크야 해서 나쁠건 없지만, 지금 코드가 보편적이긴 합니다.)
Electronic쪽에서 productNo는 null이 안되도록 강제하면 더 좋겠네요.


// TODO: 3. 전자제품들 중 인자로 주어진 제조 회사를 찾아서 하나의 배열에 반환하는 함수를 작성하시오.
public Optional<Electronic[]> groupByCompanyName(CompanyName company){

List<Electronic> temp = new ArrayList<>();

for (Electronic electronic : electronicList)
// 테스트용 임시 조건 ( electronic != null )
if (electronic != null && electronic.getCompanyName().equals(company))
temp.add(electronic);
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

이 부분은 electronic에 대한 Null 체크가 진행되어서
electronic의 companyName에 대한 equals()를 호출하였습니다.


Electronic[] companyNameGroup =
temp.isEmpty() ? null : ElectronicArrayUtil.listToArray(temp);

return Optional.ofNullable(companyNameGroup);
}

public Optional<Electronic> findByCompanyName(CompanyName company){
for (Electronic electronic : electronicList)
if (company.equals(electronic.getCompanyName()))
return Optional.of(electronic);

return Optional.empty();
}

// TODO: 4. 전자제품들 중 인자로 주어진 인증 방법을 찾아서 하나의 배열에 반환하는 함수를 작성하시오.
public Optional<Electronic[]> groupByAuthMethod(AuthMethod authMethod){

List<Electronic> temp = new ArrayList<>();

for (Electronic electronic : electronicList)
// 테스트용 임시 조건 ( electronic != null )
if (electronic != null && electronic.isContainAuthMethod(authMethod))
temp.add(electronic);

Electronic[] authMethodNameGroup =
temp.isEmpty() ? null : ElectronicArrayUtil.listToArray(temp);
Copy link
Author

@hyunsb hyunsb Apr 21, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

이부분을 제네릭을 사용한 유틸 클래스(ArrayUtil)의 사용으로
변경하고 싶었는데 ClassCastException 발생으로 실패했습니다..

따라서 임시방편으로 Electronic 클래스를 위한 유틸 클래스로 대체했습니다.
나중에 해당 문제의 해답을 찾으려 합니다.

여기서 의문이 생겼습니다.
만약에 List 을 Electronic[] 으로 캐스팅하여 반환하는 유틸성 메서드를 구현하고자 한다면
해당 메서드는 어느 클래스에 선언되는 것이 적합할까요?

새로운 유틸 클래스를 만드는 방법?
타입과 밀접한 연관이 있는 Electronic ?
실제 사용 위치와 관련된 Electronics ?

저는 개인적으로 최선책은 유틸 클래스에 선언,
차선책은 Electronic에 선언하는 것이라고 생각합니다.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

저라면 Electronics에 선언했을 것 같습니다.
음 셋 중에 static method로 정의하지 않아도 되는, private 인스턴스 메서드는 Electronics에서 선언하는거 하나네요?
그 말은 객체로서의 기능으로 사용되는 상황은 Electronics 이 친구 하나라고 생각하네요. 나머지는 말씀대로 그저 '유틸성' 기능. 객체랑 전혀 상관없는.

일단 넘어갑시다 ㅎㅎ
조금만 더 지나고 다시 대화해봐요.

하 이렇게 하면 또 궁금하셔서 잠 못 주무실테니 키워드는 'static 객체지향' 이런 쪽으로 검색해보세요
https://www.yegor256.com/2014/05/05/oop-alternative-to-utility-classes.html


return Optional.ofNullable(authMethodNameGroup);
}

public int getSize() {
return size;
}

public void setSize(int size) {
this.size = size;
}

public int getCapacity() {
return capacity;
}

public void setCapacity(int capacity) {
this.capacity = capacity;
}

@Override
public int hashCode() {
return Objects.hash(Arrays.hashCode(electronicList), size, capacity);
}

@Override
public boolean equals(Object obj) {
if (this == obj) return true;
if (obj == null || getClass() != obj.getClass()) return false;
return Objects.equals(hashCode(), ((Electronics)obj).hashCode());
}

@Override
public String toString() {
return "Users { " +
"size=" + size +
", capacity=" + capacity +
", electronicList= " + Arrays.toString(electronicList) + " }";
}

//==================================== TEST CODE ====================================//
public void add (Electronic electronic) {
if (electronicList == EMPTY_ELECTRONIC_LIST)
electronicList = new Electronic[DEFAULT_CAPACITY];
/* 배열 크기 체크하고 늘리는 로직 구현 할 것 */
electronicList[size++] = electronic;
}

public static void main(String[] args) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

오잉? 이건 지우는게 좋을 것 같아요.
혼자 테스트 하는 용도라도 진짜 프로젝트 main문에서 해보실까요?

Electronics class에서 하시면 안될 것 같아요!

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ㅎㅎ,, 이번 과제는 구현과제라서 저 혼자 테스트 해보고
멘토님도 테스트 해보실 줄 알고 놔뒀습니다.

다음부턴 지우거나
테스트코드를 JUnit을 사용해서 따로 작성하던가 하겠습니다!

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

좋습니다!

Electronic iPhone13 = new Electronic("아이폰13", CompanyName.APPLE, new AuthMethod[]{AuthMethod.FACE, AuthMethod.PIN, AuthMethod.PATTERN});
Electronic iPhone12 = new Electronic("아이폰12", CompanyName.APPLE, new AuthMethod[]{AuthMethod.FACE, AuthMethod.PIN, AuthMethod.PATTERN});
Electronic galaxyS22 = new Electronic("갤럭시S22", CompanyName.SAMSUNG, new AuthMethod[]{AuthMethod.FINGERPRINT, AuthMethod.PIN, AuthMethod.PATTERN});

Electronics electronics = getInstance();
electronics.add(iPhone13);
electronics.add(iPhone12);
electronics.add(galaxyS22);

// System.out.println(electronics);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

의미 없는 코드는 제거해주세요.


Optional<Electronic[]> authMethodGroupPIN = electronics.groupByAuthMethod(AuthMethod.FACE);
authMethodGroupPIN.ifPresent(value -> System.out.println(Arrays.toString(value)));

Optional<Electronic[]> companyNameGroupAPPLE = electronics.groupByCompanyName(CompanyName.SAMSUNG);
companyNameGroupAPPLE.ifPresent(value -> System.out.println(Arrays.toString(value)));
}
}
Loading