네로개발일기

개발자 네로의 개발 일기, 자바를 좋아합니다 !

'전체 글'에 해당되는 글 194건


반응형

객체 지향 설계 5원칙 SOLID

  • SRP (Single Responsibility Principle): 단일 책임 원칙
  • OCP (Open Closed Principle): 개방 폐쇄 원칙
  • LSP (Liskov Substitution Principle): 리스코프 치환 원칙
  • ISP (Interface Segregation Principle): 인터페이스 분리 원칙
  • DIP (Dependency Inversion Principle): 의존 역전 원칙

 

응집도는 높이고 결합도는 낮추는 객체 지향의 원칙을 지킬 수 있는 방법들

-> 결합도가 낮으면 모듈 간의 상호 의존성이 줄어들어 객체의 재사용성이나 수정, 유지보수가 용이함.

-> 응집도가 높은 모듈은 하나의 책임에 집중하고 독립성이 높아져 재사용이나 기능의 수정, 유지보수가 용이함.

 

SRP - 단일 책임 원칙

"어떤 클래스를 변경해야 하는 이유는 오직 하나뿐이어야 한다." - 로버트 C. 마틴

속성의 SRP 위배

* 가질 수 없는 속성

사람 클래스가 있고 남자만 군번을 갖는다고 가정하자. 이런 경우, 남자 클래스와 여자 클래스로 나누어 구현하는 것도 생각해보아야 한다.


* 하나의 속성이 여러 속성을 가지는 경우

데이터베이스 테이블에 존재하는 하나의 필드가 여러 속성을 가르키게 되면 정규화를 통해 단일 책인 원칙을 유지하도록 해야한다.

 

메서드가 SRP 위배

public class 강아지 {
	final static Boolean 숫컷 = true;
	final static Boolean 암컷 = false;
	Boolean 성별;

	void 소변보다() {
		if (this.성별 == 숫컷) {
			// 한쪽 다리를 들고 소변을 본다.
		} else {
			// 뒤다리 두 개로 앉은 자세로 소변을 본다.
		}
	}
}

메서드에서 분기처리가 진행되고 있다. (단일 책임 원칙을 위배하게 되었다.)

 

개선 코드

public abstract class 강아지 {
	abstract void 소변보다();
}

public class 숫컷강아지 extends 강아지 {
	void 소변보다() {
		// 한쪽 다리를 들고 소변을 본다.
	}
}

public class 암컷강아지 extends 강아지 {
	void 소변보다() {
		// 뒤다리 두 개로 앉은 자세로 소변을 본다.
	}
}

추상 메서드를 통해 행위가 다른 메서드의 구현을 하위 클래스에게 위임한다.

"상속""단일 책임 원칙"을 지키기 위한 도구로 사용한다.

 

모델링을 담당하는 추상화는 단일 책임 원칙과 가장 관계가 깊다.

=> 애플리케이션 경계(context)를 정하고 추상화를 통해 클래스의 속성과 메서드를 설계할 때 반드시 단일 책임 원칙을 고려하자

 

OCP 개방 폐쇄 원칙

소프트웨어 엔티티(클래스, 모듈, 함수 등)는 확장에 대해서는 열려있고 변경에 대해서는 닫혀 있어야 한다. - 로버트 C. 마틴

자신의 확장에는 열려있고, 주변의 변화에 대해서는 닫혀있어야 한다.

OCP의 예

JDBC

자바 애플리케이션은 JDBC 인터페이스를 완충 장치 삼아 변화에 영향을 받지 않게 된다. (변화에 닫혀있음)

데이터베이스를 다른 데이터베이스로 교체하는 것은 자신의 확장에 열려있는 것이다. (확장에 열려있음)

 

개방 폐쇄 원칙을 무시하고 프로그램을 작성하면 객체 지향의 장점인 유연성, 재사용성, 유지보수성 등의 이점을 얻을 수 없다.

=> 그 역할에 주어진 책임을 수행할 수 있다면 누구나 그 역할이 될 수 있다.

 

LSP - 리스코프 치환 원칙

서브 타입은 언제나 자신의 기반 타입(base type)으로 교체할 수 있어야 한다. - 로버트 C. 마틴

 

  • 하위 클래스 is a kind of 상위 클래스: 하위 분류는 상위 분류의 한 종류이다.
  • 구현 클래스 is able to 인터페이스: 구현 분류는 인터페이스할 수 있어야 한다.

ISP - 인터페이스 분리 원칙

클라이언트는 자신이 사용하지 않는 메서드에 의존관계를 맺으면 안된다. - 로버트 C. 마틴

단일 책임 원칙과 인터페이스 분리 원칙은 같은 문제(다중 책임)에 대한 두가지 해결책이다.

인터페이스 분할 원칙은 인터페이스 최소 원칙을 가진다.

최소주의한, 인터페이스를 통해 외부에 메서드 제공시 최소한의 메서드만 제공해야 한다.

 

DIP - 의존 역전 원칙

고차원 모듈은 저차원 모듈에 의존하면 안된다. 이 둘은 모두 다른 추상화된 것에 의존해야 한다.
추상화된 것은 구체적인 것에 의존하면 안된다. 구체적인 것에 추상화된 것에 의존해야 한다.

 

728x90
반응형
blog image

Written by ner.o

개발자 네로의 개발 일기, 자바를 좋아합니다 !

반응형

abstract 키워드 - 추상 메서드와 추상 클래스

추상 클래스: 추상 메서드를 하나라도 가지고 있는 클래스

 

* 문제점

1. 동물 클래스(상위 클래스)가 있고 동물 참조 변수를 통해 모든 동물들(하위 클래스)는 울게 하고 싶다.

2. 동물 클래스는 어떻게 울어야 하는지 모른다. (우는 메서드를 정의할 수 없다.)

 

* 해결 방법

추상 클래스와 추상 메서드를 활용한다.

추상 메서드로 하위 클래스에게 메서드의 구현을 강제할 수 있다. 

 

[ 정리 ]

  • 추상 클래스는 인스턴스를 만들 수 없다. (new 사용 불가)
  • 추상 메서드는 하위 클래스에게 메서드의 구현을 강제한다.
  • 추상 메서드를 포함하는 클래스는 반드시 추상 클래스여야 한다.

 

클래스 생성 시의 실행 블록, static 블록

public class Driver05 {
	public static void main(String[] args) {
		System.out.println("main 메서드 시작!");
		System.out.println(Animal.age);
	}
}

class Animal {
	static int age = 0;

	static {
		System.out.println("Animal class ready on!");
	}
}

Anima의 static 블록은 언제 처음 실행될까?

Animal.age 정적 속성을 사용할 때이다.

 

해당 클래스가 코드에서 맨 처음 사용될 때 스태틱 영역에 로딩되며, 이때 단 한번만 static 블록이 실행된다.

 

* 클래스가 제일 처음 사용되는 경우

  • 클래스의 정적 속성을 사용할 때
  • 클래스의 정적 메서드를 사용할 때
  • 클래스의 인스턴스를 만들 때

[ 정리 ]

  • 스태틱 블록에서 사용할 수 있는 속성과 메서드는 static 멤버 뿐이다. (일반 객체는 아직 생성 전이므로 접근할 수 없다.)
  • 프로그램 실행 시 클래스를 바로 static 영역에 로딩하지 않는 것은 메모리를 좀 더 효율적으로 사용하기 위해서이다. 

final 키워드

final 클래스

final 클래스는 상속을 허락하지 않는다. (하위 클래스를 만들 수 없다.)

 

final 변수

public class 고양이 {
	final static int 정적상수1 = 1;
	final static int 정적상수2;

	final int 객체상수1 = 1;
	final int 객체상수2;

	static {
		정적상수2 = 2;

		// 상수는 한번 초기화 되면 값을 변경할 수 없다.
		// 정적상수2 = 4;
	}

	고양이() {
		객체상수2 = 2;

		// 상수는 한번 초기화 되면 값을 변경할 수 없다.
		// 객체상수2 = 4;

		final int 지역상수1 = 1;
		final int 지역상수2;

		지역상수2 = 2;
	}
}

* final 변수 초기화 방법

final static으로 정의된 정적 상수는 선언과 동시에 초기화하거나 정적 생성자에 해당하는 static 블록 내부에서 초기화 가능

final로 정의된 객체 상수는 똑같이 객체 상수 선언과 동시에 초기화하거나 객체 생성자에서 초기화 가능하다.

 

final 메서드

public class 동물 {
	final void 숨쉬다() {
		System.out.println("호흡 중");
	}
}

class 포유류 extends 동물 {
	// 에러 발생: Cannot override the final method from 동물
	/*
	 * void 숨쉬다() { System.out.println("호흡 중"); }
	 */
}

메서드가 final이면 최종 메서드이므로 오버라이딩을 금지한다.

 

interface 키워드와 implements 키워드

인터페이스는 public 추상 메서드와 public 정적 상수만 가질 수 있다.

default 메서드가 추가되었다.

 

728x90
반응형
blog image

Written by ner.o

개발자 네로의 개발 일기, 자바를 좋아합니다 !

반응형

객체 지향의 4대 특성

1. 캡슐화: 정보 은닉

2. 상속: 재사용

3. 추상화: 모델링

4. 다형성: 사용편의

 

추상화: 모델링

객체 지향의 추상화는 곧 모델링이다.

추상화란, 구체적인 것을 분해해서 관찰자가 관심있는 특성만 가지고 재조합하는 것이다.

 

  • 객체: 세상에 존재하는 유일무이한 사물
  • 클래스: 같은 속성과 기능을 가진 객체를 총칭하는 개념

개발자가 필요한 객체는 Context(애플리케이션 경계)에 따라 달라질 수 있다.

=> 추상화란, 구체적인 것을 분해해서 관심 영역(애플리케이션)에 있는 특성만 가지고 재조합하는 것을 말한다. (모델링)

자바는 이러한 객체 지향의 추상화를 class 키워드를 통해 지원하고 있다.

 

상속: 재사용 + 확장 (extends)

상속은 계층적인 개념이 아닌 재사용과 확장으로 이해하는 것이 맞다.

상속은 분류도다.

상위 클래스로 갈수록 추상화/일반화가 되고, 하위 클래스로 갈수록 구체화/특수화가 진행된다.

 

리스코프 치환 법칙

  • 하위 클래스는 상위 클래스이다.
  • is a kind of 

상속과 인터페이스

인터페이스는 be able to 와 같이 '무엇을 할 수 있는' 형태로 만드는 것이 좋다.

 

자바 API 예시

  • Comparable 인터페이스: 비교할 수 있는
  • Runnable 인터페이스: 실행할 수 있는

 

인터페이스는 클래스가 무엇을 할 수 있다는 기능을 구현하도록 강제하게 된다.

 

  • 리스코프 치환 원칙에 의해 상위 클래스가 풍성할수록 좋다.
  • 인터페이스 분할 원칙에 의해 인터페이스 메서드는 적을수록 좋다.

 

다형성: 사용편의성

객체지향에서 다형성은 오버라이딩오버로딩이다.

 

  • 오버라이딩: 같은 메서드 이름, 같은 인자 목록으로 상위 클래스의 메서드를 재정의
  • 오버로딩: 같은 메서드 이름, 다른 인자 목록으로 다수의 메서드를 중복 정의

 

상위 클래스 타입의 객체 참조 변수를 사용하더라도 하위 클래스에서 오버라이딩한 메서드가 호출된다.

 

캡슐화: 정보 은닉

접근 제어자: private, protected, public

  • public: 모두가 접근 가능
  • protected: 상속/ 같은 패키지 내의 클래스에서 접근 가능
  • [default]: 같은 패키지 내의 클래스에서 접근 가능
  • private: 본인만 접근 가능
728x90
반응형
blog image

Written by ner.o

개발자 네로의 개발 일기, 자바를 좋아합니다 !

반응형

파일 문자셋 확인 라이브러리 / Encoding Detector / juniversalchardet 

파일의 문자셋 encoding을 확인하고 싶을 때 사용하는 라이브러리이다.

감지할 수 있는 인코딩 종류

  • Chinese
    • ISO-2022-CN
    • BIG-5
    • EUC-TW
    • HZ-GB-2312
    • GB-18030
  • Cyrillic
    • ISO-8859-5
    • KOI8-R
    • WINDOWS-1251
    • MACCYRILLIC
    • IBM866
    • IBM855
  • Greek
    • ISO-8859-7
    • WINDOWS-1253
  • Hebrew
    • ISO-8859-8
    • WINDOWS-1255
  • Japanese
    • ISO-2022-JP
    • Shift_JIS
    • EUC-JP
  • Korean
    • ISO-2022-KR
    • EUC-KR
  • Unicode
    • UTF-8
    • UTF-16BE / UTF-16LE
    • UTF-32BE / UTF-32LE / X-ISO-10646-UCS-4-3412 / X-ISO-10646-UCS-4-2143
  • Others
    • WINDOWS-1252
    • US-ASCII

 

Dependency

사용하기 위해선 dependency를 추가해줘야 한다.

maven인 경우 pom.xml에 다음 dependency를 추가한다.

<dependency>
	<groupId>com.github.albfernandez</groupId>
	<artifactId>juniversalchardet</artifactId>
	<version>2.4.0</version>
</dependency>

gradle인 경우 build.gradle에 다음 dependency를 추가한다.

implementation 'com.github.albfernandez:juniversalchardet:2.4.0'

 

Sample Code

import org.mozilla.universalchardet.UniversalDetector;

public class TestDetectorFile {

	public static void main (String[] args) throws java.io.IOException {
		if (args.length != 1) {
			System.err.println("Usage: java TestDetectorFile FILENAME");
			System.exit(1);
		}
		java.io.File file = new java.io.File(args[0]);
		String encoding = UniversalDetector.detectCharset(file);
		if (encoding != null) {
			System.out.println("Detected encoding = " + encoding);
		} else {
			System.out.println("No encoding detected.");
		}
	}
}

 

 출처 

https://github.com/albfernandez/juniversalchardet

 

GitHub - albfernandez/juniversalchardet: Originally exported from code.google.com/p/juniversalchardet

Originally exported from code.google.com/p/juniversalchardet - GitHub - albfernandez/juniversalchardet: Originally exported from code.google.com/p/juniversalchardet

github.com

 

728x90
반응형
blog image

Written by ner.o

개발자 네로의 개발 일기, 자바를 좋아합니다 !

반응형

The difference between String.valueOf and + ""(concatenation with empty string)

일을 하다가 발견한 코드...

int seqNo = 1;
System.out.println(seqNo + "");

충격적이었다. 나는 분명 String.valueOf() 메서드나 Integer.toString() 메서드를 기대했지만 왜... + "" 나오는 것인가.

 

아무튼 String.valueOf()를 찾아봤다. 

// String.java

public static String valueOf(int i) {
    return Integer.toString(i);
}

Integer.toString()을 반환한다.

// Integer.java

public static String toString(int i) {
    if (i == Integer.MIN_VALUE)
        return "-2147483648";
    int size = (i < 0) ? stringSize(-i) + 1 : stringSize(i);
    char[] buf = new char[size];
    getChars(i, size, buf);
    return new String(buf, true);
}

int 범위에 맞게 크기를 설정해주고 하나씩 넣어준다.

 

그리고 두 번째 의문, 빈 문자열을 + 연산으로 문자열 연결을 해주는 것과 String.valueOf() 메서드와의 성능 차이는 얼마나 있을까?

// 빈 문자열을 연결해줄 경우, StringBuilder를 사용해서 String을 만들어준다.
public void foo(){
    int intVar = 5;
    String strVar = intVar+"";    
}
public void foo();
  Code:
   0:   iconst_5
   1:   istore_1
   2:   new     #2;			//class java/lang/StringBuilder
   5:   dup
   6:   invokespecial   #3;	//Method java/lang/StringBuilder."<init>":()V
   9:   iload_1
   10:  invokevirtual   #4;	//Method java/lang/StringBuilder.append:(I)Ljava/lan
g/StringBuilder;
   13:  ldc     #5; 		//String
   15:  invokevirtual   #6; //Method java/lang/StringBuilder.append:(Ljava/lang/
String;)Ljava/lang/StringBuilder;
   18:  invokevirtual   #7; //Method java/lang/StringBuilder.toString:()Ljava/la
ng/String;
   21:  astore_2
   22:  return

 

// String.valueOf()를 사용할 경우, String의 static 메서드를 사용한다.
public void bar(){
    int intVar = 5;
    String strVar = String.valueOf(intVar);
}
public void bar();
  Code:
   0:   iconst_5
   1:   istore_1
   2:   iload_1
   3:   invokestatic    #8; //Method java/lang/String.valueOf:(I)Ljava/lang/Stri
ng;
   6:   astore_2
   7:   return

 

String.valueOf() 메서드를 사용하여 문자열로 바꿔주는 것이 좀 더 효율적이다.

 

 출처 

https://stackoverflow.com/questions/7752347/string-valueof-vs-concatenation-with-empty-string

 

String valueOf vs concatenation with empty string

I am working in Java code optimization. I'm unclear about the difference between String.valueOf or the +"" sign: int intVar = 1; String strVar = intVar + ""; String strVar = String.valueOf(intVar);

stackoverflow.com

 

728x90
반응형
blog image

Written by ner.o

개발자 네로의 개발 일기, 자바를 좋아합니다 !