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

  1. 2019.05.20 spring , spring boot 차이
  2. 2019.04.28 [자료구조]List
  3. 2019.04.27 factory method pattern
  4. 2019.04.27 singleton-pattern
  5. 2019.04.23 Garbage Collector
  6. 2019.04.22 jvm 메모리 구조
  7. 2019.04.14 3tier-module(gradle-muti-project)
  8. 2019.02.23 [객체지향] JAVA SOLID 원칙

1. 스프링부트는 tomcat를 내장하면서, Servlet Container에 종속되던 Web Application이 역으로 

 Web Application에 Servlet Container에 종속되는 형태이다.

 

2. Dependency 간의 버전 호환성등으로 문제되던게 해결되었다 (spring-boot-starter.. )

3. 일반적으로 쓰이는 설정을 기본으로 제공한다.(별도로 설정하지 않으면 기본설정대로)

4. Micro service  구성의 용이함 (어플리케이션 환경을  쉽고 빠르게 구성함)

 

개인적인 견해

작은 규모의 어플리케이션을 실행하기 위해 어플리케이션보다 큰 WAS를 설치해야한다.

이렇게 비교적 규모가 작은 어플리케이션에 was 를 설치하는것은 효율적이지 않다

이런경우,

stand alone 스타일의 어플리케이션을 구동해야할 경우엔 스프링부트에서 제공되는 임베디드 컨테이너에서 자신의

어플리케이션을 실행시키는게 효율적일 수 있다.

그러나 규모가 큰 웹사이트에서는 MVC형태로 만들어 WAS에 배포하는 스타일이 낫다.

WAS에서 관리되는 데이터 소스나 메시지 서비스를 이용할수 있기 때문이다.

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

'FRAMEWORK > Spring Boot' 카테고리의 다른 글

[intelliJ] Spring boot 시작하기 -1  (1) 2017.05.18
Posted by 양승아
:

[자료구조]List

JAVA/JAVA 2019. 4. 28. 16:37 |

List

리스트는 특정 타입 값들이 순차적으로 정렬된 컬렉션입니다.

LinkedList, ArrayList 클래스를 일반적으로 사용합니다.

리스트는 자바의 배열하고 다릅니다. 

리스트는 크기 지정에 한계가 없으므로 리스트를 사용하기 전에 크기를 지정할 필요가 없습니다.

 

LinkedList 와 ArrayList 가 각각 적합한 경우에 대해 알아보겠습니다.

 

배열과 리스트 차이

- 배열은 정의할 때 크기를 지정해야 함.

- 배열의 원소에 인덱스값을 지정하여 직접 접근가능(랜덤접근)

- 배열 크기를 늘려야할때 새로운 배열을 만들고 재정렬하는 절차를 가짐 

- 정수 타입 배열은 final 을 지정할 수 없음

 

 

ArrayList 

리스트의 데이터로 배열을 사용하는 List 인터페이스이다.

- ArrayList 클래스 생성시 배열의 초기 크기 지정할 수 있음 (default 10)

- 크기가 추가될때 마다 자동으로 배열을 재할당 함 (단,시간이 소요되고 메모리용량 소모함-> 큰 컬렉션을 이용할거면 미리 크기를 지정함)

- ArrayList 시작위치나 중간 위치에 값을 추가하려고 하면 모든 원소는 공간을 위해 이동해야됨 (=>크기가 크다면 연산량이 많은 작업임)

- 배열 크기 재할당은 단반향으로 이루어짐

- 원소를 줄여도 배열 크기는 줄지않음

 

 

LinkedList

연결리스트를 구현 할수 있는 또다른 리스트 구현체입니다.

원소들을 저장하는데 배열을 이용하지 않고 리스트안에서 다음 원소를 가리키는 내부 객체를 이용합니다.(노드참조값)

 

 

결론

ArrayList 순차적인 추가/삭제 유리함

인덱스를 참조하고 있어서 검색할때 LinkedList 보다 빠르다.

 

LinkedList 는 비순차적인 추가/삭제에 유리함

 

 

 

 

'JAVA > JAVA' 카테고리의 다른 글

Garbage Collector  (0) 2019.04.23
jvm 메모리 구조  (0) 2019.04.22
[객체지향] JAVA SOLID 원칙  (0) 2019.02.23
제네릭 메소드  (0) 2017.05.17
제네릭 개념 알기  (0) 2017.05.16
Posted by 양승아
:

factory method pattern 

주의! 팩토리 메소드와 추상팩토리 패턴은 다르다.

 

팩토리 메소드 패턴

객체를 만들어내는 부분을 서브클래스에 위임하는 하는 패턴이다.

키워드를 호출하는 부분을 서브클래스에 위임하는것으로 팩토리 메소드 패턴은 객체를 만들어내는 공장(팩토리)라고 이해하면 된다.

 

로봇으로 예제를 들어보자.

여러 종류의 로봇을 생산하는 공장도 있어야한다. 

로봇과 로봇공장을 만들어서 예제를 돌려봅니다.

 

<Robot>

package pattern.factory;

public abstract class Robot {
	public abstract String getName();
}
public class SuperRobot extends Robot {
	@Override
	public String getName() {
		return "SuperRobot";
	}
}
public class PowerRobot extends Robot {
	@Override
	public String getName() {
		return "PowerRobot";
	}
}

 

 

<Robot Factory>

로봇의 팩토리 클래스이다.

public abstract class RobotFactory {
	abstract Robot createRobot(String name);
}

아래 클래스는 기본 팩토리클래스를 상속받아 실제 로직을 구현한 팩토리이다.

public class SuperRobotFactory extends RobotFactory {
	@Override
	Robot createRobot(String name) {
		switch( name ){
			case "super": return new SuperRobot();
			case "power": return new PowerRobot();
		}
		return null;
	}
}

아래 클래스도 기본팩토리를 상속받아 실제 로직을 구현한 팩토리지만 위와 다른점은 클래스이름을 String 으로 받아서 직접 인스턴스 생성한다.

package pattern.factory;

public class ModifiedSuperRobotFactory extends RobotFactory {
	@Override
	Robot createRobot(String name) {
		try {
			Class<?> cls = Class.forName(name);
			Object obj = cls.newInstance();
			return (Robot)obj;
		} catch (Exception e) {
			return null;
		}
	}
}

 

<Test Code>

public class FactoryMain {
	public static void main(String[] args) {

		RobotFactory rf = new SuperRobotFactory();
		Robot r = rf.createRobot("super");
		Robot r2 = rf.createRobot("power");

		System.out.println(r.getName());
		System.out.println(r2.getName());

		RobotFactory mrf = new ModifiedSuperRobotFactory();
		Robot r3 =  mrf.createRobot("pattern.factory.SuperRobot");
		Robot r4 =  mrf.createRobot("pattern.factory.PowerRobot");

		System.out.println(r3.getName());
		System.out.println(r4.getName());
	}
}

결과

main() 에서 new() 키워드가 없다는것을 확인할 수 있음.

객체 생성을 팩토리에 위임한 결과이다. 

main() 에서는 팩토리를 통해 원하는 로봇 객체를 얻는다.

팩토리 메소드 패턴을 사용하는 경우 직접 객체를 생성해 사용하는것을 방지하고 서브 클래스에 위임함으로써 효율적인 코드 제어를 할 수 

있고 의존성을 제거한다.

 

팩토리 메소드 패턴을 사용하는 이유는 클래스간의 결합도를 낮추기 위한것이다. 

즉, 로봇 클래스에 변경이 일어나도 다른 클래스에도 영향을 주지않는다.

팩토리 메소드 패턴을 사용하는 경우 직접 객체를 생성해 사용하는것을 방지하고 서브 클래스에 위임함으로써 보다 효율적인 코드 제어

할 수 있고 의존성을 제거한다.

결과적으로 결합도를 낮출수 있다.

 

 

'JAVA > Design patten' 카테고리의 다른 글

singleton-pattern  (0) 2019.04.27
Decorator Pattern (데코레이터 패턴)  (0) 2015.09.03
옵저버 패턴의 정의  (0) 2015.08.21
Posted by 양승아
:

singleton-pattern

JAVA/Design patten 2019. 4. 27. 17:47 |

Singleton-pattern

단 하나의 인스턴스를 생성해 사용하는 패턴

 

why?

고정된 메모리 영역을 얻으면서 한번의 new로 인스턴스를 사용하기 때문에 메모리 낭비를 방지할 수 있음

또한,싱글톤으로 만들어진 클래스의 인스턴스는 전역 인스턴스이기 때문에 다른 클래스의 인스턴스들이 데이터를 공유하기 쉽다

커넥션 풀, 스레드 풀 등 객체생성시 싱글톤 사용

 

1. eager initialization  (이른 초기화)

싱글톤 패턴중에 가장 기본적인 싱글톤 패턴이다

이른 초기화 방식은 싱글톤 객체를 미리 생성해 놓은 방식이다.

전역변수로 instance 변수 생성하고 private static 선언하여 직접 바로 접근할 수 없도록 합니다.

생성자에도 private 접근 제어 키워드를 붙여 다른 클래스에서 new EagerInitialization() 방식으로 새로운 인스턴스 생성하는 것을 방지한다.

오로지 정적메소드인 getInstance() 메서드를 통해 인스턴스를 접근하도록 하여 동일한 인스턴스를 사용하는 기본 싱글톤원칙을 지키게한다.

/**
 *
 * 가장 기본적인 singleton pattern
 * new EagerInitialization () 될때 어떠한 예외처리도 할 수 없다는것이 단점
 */
public class EagerInitialzation {

	//private 으로 선언하여 외부에서 접근 불가
	//static 으로 인스턴스화 없이 사용 가능함
	private static EagerInitialzation instance = new EagerInitialzation();

	// private 으로 생성자 선언하여 new 키워드로 인스턴스 생성 불가능
	private EagerInitialzation(){
		System.out.println("call EagerInitialzation constructor");
	}

	//instance의 직접 접근도 불가능하고 생성자도 불가능하기 때문에 getInstance() 로 만 인스턴스 가질수있음
	public static EagerInitialzation getInstance(){
		return instance;
	}
}

 

2. Static block initialization

이른초기화와 같은 방식으로 초기에 인스턴스 만들어놓지만 static 구문에 로직을 추가하여 수행하는 패턴이다

logic을 담을수 있기 때문에 복잡한 초기변수 셋팅이나 예외처리를 위한 구문을 담을수 있다.

 

/**
 *
 * Static block initialization
 * logic을 담을수 있기 때문에 복잡한 초기변수 셋팅이나 위와 같이 에러처리를 위한 구문을 담을수 있다.
 */
public class StaticBlockInitialization {

	private static StaticBlockInitialization instance;

	private StaticBlockInitialization (){ }
	// static 으로 정의하여 초기화 블럭을 이용하여 클래스가 로딩될때 최초 한번 실행하게 됨.
	static {
		try {
			System.out.println("instance create...");
			instance = new StaticBlockInitialization();
		}catch (Exception e){
			throw new RuntimeException("Exception creating StaticBlockinitalation instace.....");
		}
	}

	public static StaticBlockInitialization getInstance(){
		return instance;
	}
}

 

 

3. Lazy initialization (게으른 초기화)

게으른 초기화는 인스턴스를 사용하는 시점에 사용한다. 

instance 변수를 private static 으로 전역변수로 만들고 생성자도 private 로 선언하여 외부에서 생성 못하게 한다.

오직 getIntance() 메소드를 통해 인스턴스 생성 및 호출되는데, 최초 호출일 경우 인스턴스 객체 생성한다.

만약 멀티 쓰레드를 방식에서 getInstance() 를 두번 호출하게 되면 인스턴스가 두번 생성될 수 있는 문제점이 있다.

 

/**
 * Eager initialization,static block 방법은 클래스가 로딩될때 인스턴스 생성하기 때문에 프로그램이 커지만 부담이 될수 있다.
 * Lazy 초기화는 인스턴스를 사용하는 시점에 사용한다.
 * 만약 멀티 쓰레드 방식이라서 getinstance()를 두번 호출하게 되면 두번 생성 될수 있다.
 */
public class LazyInitialization {

	private static LazyInitialization instance;
	private LazyInitialization(){};

	public static LazyInitialization getInstance(){
		if (instance == null)
			instance = new LazyInitialization();
		return instance;
	}
}

 

4.Thread Safe Lazy initialization(스레드 안전한 늦은 초기화)

Lazy 싱글톤 방식에서 thread safe 문제가 있어 이를 보완하기 위해 멀티쓰레드에서 스레드들이 동시 접근하는

동시성을 synchronized 키워드를 이용해 해결하는 방식이다.

 

/**
 * sychronized 블록으로 인해, 수 많은 쓰레드 들이 인스턴스 호출하게 되면 높은 cost 비용으로 인해
 *  프로그램 전반에 성능저하가 일어난다.
 *
 */
public class ThreadSafeInitialization {
	private static ThreadSafeInitialization instance;
	private ThreadSafeInitialization(){}

	//여러 thread 들이 동시에 접근해서 인스턴스를 생성시키는 위험은 없어짐!
	public static synchronized ThreadSafeInitialization getInstance(){
		if (instance==null)
			instance = new ThreadSafeInitialization();
		return instance;
	}
}

synchronized 키워드를 사용할 경우 자바 내부적으로 해당 영역이나 메서드를 lock,unlock 처리하기때문에 많은 cost가 발생함

=> 성능저하됨!

 

4-1. Thread Safe Initialization + double - checked locking 기법 싱글톤 패턴

위에 Thread safe initialization 에서 synchronized 처리된 메서드가 성능저하가 발생되어 완화하기 위해

Double checked locking 기법을 사용한다.

instance가 null 일 경우에 synchronized 블럭에 접근하고 한번더 instance의 null 유무를 체크한다.

if문 두번다 null 일 경우 new를 통해 인스턴스화시킨다.

그후 instance 가 null이 아니기때문에 synchronized 블록을 타지 않는다.

Double checked locking 으로 성능저하 줄임

 

public class ThreadSafeLazyInitialization {
 
    private static ThreadSafeLazyInitialization instance;
 
    private ThreadSafeLazyInitialization(){}
     
    public static ThreadSafeLazyInitialization getInstance(){
        //Double-checked locking
        if(instance == null){
            synchronized (ThreadSafeLazyInitialization.class) {
                if(instance == null)
                    instance = new ThreadSafeLazyInitialization();
            }
 
        }
        return instance;
    }
}

 

'JAVA > Design patten' 카테고리의 다른 글

factory method pattern  (0) 2019.04.27
Decorator Pattern (데코레이터 패턴)  (0) 2015.09.03
옵저버 패턴의 정의  (0) 2015.08.21
Posted by 양승아
:

Garbage Collector

JAVA/JAVA 2019. 4. 23. 11:26 |

Garbage Collertor 알고리즘 동작 방식 알아보자.

- Serial GC

- Parallel GC

- Parallel Old GC

- Concurrent Mark - Sweep GC

- G1 (Garbage First)GC

 

Serial GC

-XX:+UseSerialGC 

young/old 영역을  Single CPU를 사용한다.(현재 거의 사용 안함)

 

Parallel GC 

-XX:+UseParallelGC

young 영역은 멀티쓰레드로 처리되지만, Old 영역은 싱글쓰레드로 처리된다.

 

 Parallel Old GC

-XX:+UseParallelOldGC

young/old 영역 모두 멀티 쓰레드 방식으로 처리된다.

 

Concurrent Mark & Sweep GC (CMS)

-XX:+UseSerialGC

영역의 크기가 클 때 적합한 방식이다.

Suspend Time 분산하여 응답시간을 개선한다

비교적 자원이 여유있는 상태에서 GC 의 Pause Time 을 줄이는 목적으로 사용한다.

 

 

*Minor GC

eden 이 가득차면 삭제할 object들을 찾는다.(참조하지 않는 객체)

참조중 (계속 사용할 객체)면 Survior 영역으로 옮겨둠

참조가 없으면 남겨둔다(eden)

참조중인 객체가 모두 넘어가면 Eden을 싹 청소함

 

* Full GC

 old 영역: 접근 불가능 상태로 되지 않아 young 영역에서 살아남은 객체가 여기로 복사됨

대부분 Young 영역보다 크게 할당 하며,크기가 큰 만큼 young 영역보다 Gc는 적게 발생함

old 영역에 데이터가 가득차면 GC 를 수행하는데 GC 알고리즘 수행됨.

 

 

 

 

 

 

 

'JAVA > JAVA' 카테고리의 다른 글

[자료구조]List  (0) 2019.04.28
jvm 메모리 구조  (0) 2019.04.22
[객체지향] JAVA SOLID 원칙  (0) 2019.02.23
제네릭 메소드  (0) 2017.05.17
제네릭 개념 알기  (0) 2017.05.16
Posted by 양승아
:

jvm 메모리 구조

JAVA/JAVA 2019. 4. 22. 21:24 |

jvm 이란?

Jave Virture Machine 의 약자로 자바 가상머신이라 부른다.

자바와 운영체제사이에서 중계자 역할을 한다.

자바가 운영체제 종류에 영향받지 않고 돌아갈 수 있도록 한다.

메모리 관리를 자동으로 해준다(GC)

 

 

JVM은 운영체제와 플랫폼 종류에 의존적이지 않고 독립적으로 JAVA 프로그램이 실행된다.

 

<자바실행과정>

java Compiler 에 의해 .java 파일은 Byte code로 변환된다

Class Loader는 변환된 Byte Code 파일을 Jvm 내로 class를 로드하고 Link 작업을 통해 배치등 일련의 작업을 한다.

런타임시 .class를 load 한다.

Execution Engine(실행엔진) Class Loader를 통해 JVM 내부로 넘어와 Runtime Data Area에 배치된 Byte Code 들을 명령어 단위로 실행시킴

* GC 는 어플리케이션이 생성한 객체 생존 여부를 판단하여, 더이상 참조되지 않거나 null 인 객체의 메모리를 해체시켜 메모리를 반납을 함

* Runtime Data Area(JVM) 런타임 데이터 영역은 JVM 메모리로 java 어플리케이션이 실행하면서 할당받은 메모리 영역이다

 

 

Method Static Area : 클래스,변수,Method,Static변수,상수 정보들이 저장되는 영역

Heep Area : new 명령어로 생성된 인스턴스와 객체가 저장되는 구역. GC 이슈는 이영역에서 일어남

Stack Area : Method 내에서 상용되는 값들(매개변수, 지역변수, 리턴값) 메소드가 호출될때 LIFO 로 생성됨.실행이 완료되면 LIFO 삭제

PC Register : CPU의 Register와 비슷한 역할함. 현재 수행중인 JVM명령의 주조값이 저장됨

 

* Method Satic Area , heep..영역은 모든 스레드에서 공유할 수 있다.

 

Young Generation : 객체가 생성될때 마다 저장된다. 즉 막 생성된 객체들의 인큐베이터이다. 생성된 기간이 흐르고 우선순위가 낮아지면

Young 세대의 객체들은 Old 세대로 이동하게 된다. 이영역은 객체가 사라질 때는 Minor GC 수행된다.

Old Generation : young Generation 영역에 있는 객체가 오래되서 저장되는 공간이다.이영역에서 사라질때는  Full GC 수행됨

Permanent Generation : 클래스 로더에 의해 로드되는 클래스,메소드 등에서 대한 메타정보가 저장되는 영역으로 JVM 에 의해 사용됨

 

'JAVA > JAVA' 카테고리의 다른 글

[자료구조]List  (0) 2019.04.28
Garbage Collector  (0) 2019.04.23
[객체지향] JAVA SOLID 원칙  (0) 2019.02.23
제네릭 메소드  (0) 2017.05.17
제네릭 개념 알기  (0) 2017.05.16
Posted by 양승아
:

gradle을 이용해서 multi project  생성하기

구조는  web, model, api  3tier로 구성

 

web는 프레젠테이션에 해당하는 프로젝트

model는 data access object 해당하는 프로젝트 web, api 에서 참조한다.

api는 비즈니스 로직을 담당하는 프로젝트 

 

아래와 같이 구성됨

 

 

프로젝트 구조 

프로젝트 구조

 

gradle setting 

gradle setting file

sub project 를  root에 gradle setting 파일에  include 해주면 멀티프로젝트 생성됨

 

root(상위) gradel.build 파일

subproject 에 해당 서브프로젝트에 해당되는 build 설정

allproject 에 모든 프로젝트에 설정

project('') 각 프로젝트 build 설정

* module-dao 의존 설정 !

 

WEB  구조

* Web context 에view resolver,filter setting 

 

API 구조

root application context  설정

 

WEB 에서 요청 처리 

WEB 에서 API 호출할때 GET,PUT,DELETE,POST 을 사용하기 위해 RESTtemplete  사용하여 호출함 

 

Posted by 양승아
:

#SOLID 원칙

java 가 객체지향언어로서 객체지향의 solid 5대 원칙을 알아보자.



#Single Responsibility principle (SRP)


작성된 클래스는 하나의 기능만 가져야 한다. 

하나의 책임에 집중 -> 책임 영역 확실해짐

다른 책임의 변경으로 연쇄작용에서 자유로워짐

유지보수가 용이해짐 

도메인이해가 필요함


적용방법

- 두클래스가 중복되고비슷한 책임을 갖고 잇다면 부모클래스로 정의하여 부모클래스에 위임하고 

각각 클래스에서는 유사한 책임은 부모클래스에 명백히 위임하고 각각 다른 기능을 정의한다.


적용사례 

/**
*
* single responsibility principle 적용되기 전 클래스
*
*
*/
public class Guitar {

//생성자
public Guitar(String serialNumber,Double price, Maker maker, String model, int stringNum) {

}

private String seriaNumber;
private Double price;
private Maker maker;
private String model;
private int stringNum;

}


우선 변화 요소 유무 부터 나누면 

serialNumber 은 고유정보이다. 다른 클래스와 구분되는 정보이다.

price,Meker,model,stringNum 등은 특성 정보로 변경이 발생 할 수 있는 부분이다. 

따라서 특정 정보군에 변화가 발생하면 항상해당 클래스를 수정해야 하는 부담이 발생하게 됨으로 이부분을 SRP 이 적용대상이 된다.


변경이 예상되는 객체들을 따로 분리한다. 

model,price,Maker,StringNum 을 Spec 클래스에 모아둔다


class Gutar{

public Gutar(String serialNumber,GuitarSpec spec ) {
}
}


class GuitarSpec{
double price;
String model;
Maker maker;
int StringNumber;
}

만약 GuitarSpec 에 name 이라는 필드가 추가되도 guitar 클래스에서 책임지지 않아도 된다. 스펙 클래스에서만 추가해주면 된다.

이렇게 각 객체간 응집력을 높이고 결합력이 있다고 분리시켜 객체간의 순 작용 할 수 있도록 한다.


#Open Close Principle(OCP)


확장에는 열려있고 변경에는 닫혀있어야 한다.

즉 추가 요구 사항이나 변경 사항이 있더라도 기존 구성요소에 수정이 일어나지 않고 확장하여 재사용할 수 있어야함.

OCP는 관리가능하고 재사용 가능한 코드를 만드는 기반임

추상화와 다형성을 통해 OCP 를 가능케함


적용방법

- 변경(확장)될 것과 변하지 않을 것을 구분

- 이 두 모듈이 만나는 지점에 인터페이스 정의(?) -> 공통되는 부분을 부모클래스로 만들기

- 구현에 의존하기보다 정의한 인터페이스에 의존하도록 코드 작성


예를 들어보자 SRP 예에 들었던 Guitar 뿐만 아니라 바이올린 ,첼로 등등등 악기들을 추가 해야된다고 생각해보자.

Guitar, GuitarSpect 는 오로지 기타를 위한 클래스로 만들어졌다. 결합도 높게 설계햇다면 확장적이지 못할 뿐더러 많은 수정이 발생되어 유지보수가 어렵다.

기타와 바이올린에 getPlay()라는 메소드를 추가한다고 가정하면 해당 클래스 모두 수정이 필요하다.


OCP 원칙대로 수정해보자

우선 기타와 추가될 악기들의 공통 속성들을 모두 담을수 있는 악기 인터페이스와 추가될 알기 스텍들과 공통이 될수 있는 속성을 스펙 인터페이스로 만든다.

악기, 악기 스펙은 수정이 없으면서 악기는 계속 확장적이게 된다. 상위클래스나 인터페이스는 일종의 완충 장치인것이다.




악기스펙 인터페이스에서는 가격정보,모델정보,연주하기() 메서드를 정의하고 각각 기타,바이올린 등 추가되는 악기 클래스에서 입맛에 맞게 메서드를 재저의하면 되다.

더 깔금한 예시로 postgreSQL, Oracle, sybase 데이터베이스에 모두 확장적이면서 자바어플리케이션 입장에서 수정은 폐쇄적인것 임을 알아야한다. 

이것이 바로 OCP 이다.


 

ocp jdbc interface에 대한 이미지 검색결과





#Liskov Substitution Principle(LSP)


하위 클래스의 인스턴스는 상위형 객체 참조 변수에 대입해 상위 클래스의 인스턴스 역할을 하는데 문제가 없어야 한다.

즉 하위클래스가 상위클래스 역할을 대신할 때 논리적으로 맞아야 한다.


' A is a kind of B  즉 a kind of B is A '


잘못된 상속 관계 : 엄마와 딸 // 딸은 아버지의 한 종류다 ?  NO !!

올바른 상속 관계 : 고양이와 동물 // 고양이는 동물의 한 종류다 ? YES !!


객체지향에서의 상속은 상위,하위 클래스를 설계하는 것이 계층이 아니라 분류이다. 상속은 확장이다 라고 생각해야한다.


아래 간단한 예제로 이해해보자.

void fuction(){
LinkedList list = new LinkedList();
modify(list);
}

void modify(LinkedList list){
list.add("test");
doSomethingWith(list);

}

List만 사용할 것이라면 이 코드도 문제는 없다. 만약 속도 개선을 위해 HashSet을 사용해야 하는 경우가 발생한다면 LinkdList 를 다시 HashSet으로 어떻게 변경할수 있을까 ? LinkdList 와 HashSet 은 Collection 인터페이스를 상속하고 있으므로 아래와 같이 구현할수 있다.


void fuction(){
Collection collection = new HashSet();
modify(collection);
}

void modify(Collection collection){
collection.add("test");
doSomethingWith(collection);

}

Collection 프레임 워크가 LSP를 준수하지 않았다면 Collection 인터페이스를 통해 수행하는 작업이 제대로 동작하지 않았을것이다.

LSP 준수하여 HachSet는 modify() 메소드 동작이 가능하다. 또한 OCP 구조도 된다. modify()는 컬렉션에는 확장이 열러있고 modify 에 변경은 닫혀있다.



#InterFace Segregation Principle(ISP)


인터페이스 분리 원칙은 SRP와 같은 맥락의 대한 다른 해결책을 제시하는 것이다. 

한 클래스에 너무 많은 책임을 주어 상황에 관련 되지 않은 메소드 까지 구현되어 있다면, 

SRP 원칙은 기존 클래스를 여러 책임 단위로 쪼갠다.

하지만 ISP는 기존 클래스를 그대로 두고 인터페이스 최소주의 원칙에 따라 각 상황에 맞는(책임) 기능만 제공하도록 인터페이스로 분리한다고 생각하면 된다.


job클래스에 요리하기 (), 기도하기(), 사격하기(), 개발하기() 메소드가 있다. 하지만 모든 사람 하는 기능은 아니다.



public class Job {

void shoot(){};
void pray(){};
void cook(){};
void develop(){};

}


각각 직업 특성에 맞게 책임을 인터페이스로 분리해보자

우선 책임별 인터페이스 생성한다.


interface Shootable {
void shoot();
}

interface Cookable {
void cook();
}


interface Prayable {
void pray();
}


interface Developable {
void develop();
}


그다음 다중구현을 통해 각각 메서드를 오버라이딩해서 재정의한다.


public class job implements Shootable,Developable,Cookable,Prayable{
@Override
public void shoot() {
System.out.println("사격한다.");
}

@Override
public void cook() {
System.out.println("요리한다");
}

@Override
public void pray() {
System.out.println("기도한다.");
}

@Override
public void develop() {
System.out.println("개발한다.");
}
}

public class ISPmain {

public static void main(String[] args){

Developable developer = new job();
developer.develop();

Cookable cooker = new Person();
cooker.cook();
}
}

직업중에 개발자라면 위에 예제와 같이 참조형을 Developable 타입으로 정의하고 job 인스턴스를 받으면 개발자는 develop() 기능만 할당 받게 된다.

상황에 맞게 기존 클라이언트는 변경없이 관련 메소드만 제한을 강제하여 사용할 수 있다.


#Dependency Inversion Principle (DIP)


'추상화 된 것은 구체적인 것에 의존하면 안된다. 구체적인 것이 추상화 된 것에 의존해야 한다.'


즉 자신보다 변하기 쉬운 것에 의존하지 마라.

구체적으로 추상클래스 또는 상위클래스는 구체적인 구현클래스 또는 하위클래스에게 의존적으면 안된다. 

왜냐면 구체적인 클래스는 코딩에 있어서 가장 전면적으로 노출되고 사용되기 때문에 시시때때로 변화할 수 있으므로 변화에 민감하다.


예를 들면 BMW 자동차는 스노우타이어를 장착하고 있다. 하지만 스노우 타이어는 계절의 영향을 받아 겨울 지나고 다른 타이어로 교체할것이다.



BMW가 자신보다 더 변화에 민감한 스노우 타이어를 의존하고 있다. 이 의존을 일방적인 방향을 역전 시켜보자



자신 보다 변하기 쉬운 것에 의존하던것을 추상화 된 인터페이스나 상위클래스를 두어 변하기 쉬운것의 변화에 영향 받지 않게 의존 방향을 역전시켰다.

타이터 인터페이스에 의존하면서 직접적으로 스노우,일반타이어와 의존하는것을 피했다.

또 스노우,일반 타이어는 기존에 어떤 것도 의존하지 않았지만 인터페이스를 의존해야한다. 이것이 Dependency Inversion Principle 이다.


#마무리


객체지향 OOP 의 4대 요소인 캡슐화,상속,추상화,다형성이라는 재료와 객체지향 성계 SOLID 원칙을 통해 객체지향을 어떻게 설계하는지 배웠다.

결국 실무에서 설계를 잘해야 유지보수 측면에서 굉장히 용이하고 개발 시간과 비용을 절감할수 있다. 

 


'JAVA > JAVA' 카테고리의 다른 글

Garbage Collector  (0) 2019.04.23
jvm 메모리 구조  (0) 2019.04.22
제네릭 메소드  (0) 2017.05.17
제네릭 개념 알기  (0) 2017.05.16
다형성  (0) 2015.08.28
Posted by 양승아
: