네로개발일기

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

'2022/05'에 해당되는 글 12건


반응형

객체 지향 설계 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

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