관리 메뉴

LC Studio

JAVA & Spring 강의 (자바 인강 7주차) 스프링입문 본문

Java/Java&Spring 기초 강의

JAVA & Spring 강의 (자바 인강 7주차) 스프링입문

Leopard Cat 2022. 5. 4. 22:33

객체지향이란?

객체지향의 등장

-1970년대 이전에는 "절차 지향" 사용, logic을 순차적으로 처리하는 방식

-프로그램의 복잡도가 증가하면서 -> 유지보수, 개발기간 등 비효율 발생

-위의 이유로 효과적인 개발방식을 채택하다보니 추상화, 상속, 은닉, 재사용, 인터페이스 등 등장

 

-새로운 시각, 사물을 있는 그대로 모델링 -> 행위와 속성을 정의

- 사물 -> 객체 (Object)

- 사물의 행위 -> 행위 (Method)

- 사물의 속성 -> 변수 (Variable)

 

객체 설계

- 객체 == 사물 == Object

ex)

자동차

속성 : 이름, 번호, 모델명 ...

 

-사물의 행위 == Method

ex)

자동차

속성 : 주행거리, 연비계산, 번호교체 ...

 

객체의 3가지 요소

- 상태유지 (객체의 상태)

객체는 상태 정보에 대한 속성이 변수로 정의되어야 한다.

- 기능제공 (객체의 책임)

Method를 통해 기능이 제공되어야함.

- 고유식별자 제공 (객체의 유일성)

고유한 식별자를 가져야 한다.

 

물리객체

-실제 사물이 존재

ex)급여관리 시스템 - 직원, 월급통장 ...

 

개념객체

-business logic 처리

ex)사용자 관리 시스템 - 사용자 객체의 마지막 접속일자를 이용하여 계정만료, 비밀번호 초기화 로직


객체지향의 4대 특성

1. 캡슐화

객체의 속성(Variable)을 보호하기 위해 사용

 

Method 설계

- 속성에 대해 상태를 변경하는 Method가 있어야함.

- 실물 객체가 가진 기능을 모두 제공해야함.

- 관련성이 있어야함, ex) 전원 on/ off

- 객체안의 Method는 객체안의 속성을 처리해야함.

- Method 실행에 필요한 값들은 객체 형태가 아닌 매개변수의 형태로 전달되어야함.

 

- Getter / Setter 활용, 외부에서 직접접근 X

- CRUD Method / Business Logic Method / 객체의 생명주기처리 Method / 객체의 영구성관리 Method

 

장점

- 추상화 제공 (외부에서 Method를 이해할 필요 없이, 단순 호출로 사용가능 )

- 재사용성 향상 (Method는 모두 캡슐화 형태로 제공)

- 무결성 (변수는 private로 선언하여 접근 안됨 / )

 

2. 상속

속성의 상속이 아닌, 하위로 내려갈수록 구체화되는것!

 

상속의 효과

-프로그램 구조에 대한 이해 쉬움(상위 객체의 속성을 보고, 하위 객체의 속성구조를 어느정도 알 수 있음)

-재사용성 향상 (새로 정의필요없이, 상속받아서 활용)

-확장성 향상 (일관된 형태로 클래스 객체 추가 가능)

-유지보수 향상(상속을 활용해 일괄되게 수정 가능)

 

3. 다형성

하나의 객체가 여러개의 형태로 현화하는 것

오버라이딩을 통해 가능

ex) move() 메서드를 호출하면, if문을 통해 객체 하나하나의 속성을 지정하는 것이 아닌,

객체 자체에서 오버라이딩을 통해 자신만의 move()메서드를 설정

즉,

private void unitMove(unit unit){

    unit.move()

}

이렇게만 호출해도 각 unit은 오버라이딩한 메서드대로 각각 다르게 움직임

 

4. 추상화

모델링이다.

즉 각 객체의 속성, 특성 등을 분리해서 재조합하는 부분.


객체지향 설계 5원칙 SOLID

응집도와 결합도

결합도

-클래스 간의 상호의존 정도

-결합도가 낮으면 객체의 재사용 및 유지보수 유리

ex) A - B -C 의존 A변경 시 B,C 도 수정해야함

 

응집도

-하나의 모듈 내부에 존재하는 구성 요소들의 기능적 관련성

-독립성이 높아져 재사용 및 유지보수 용이

 

1. SRP (Single Responsibility Principle) 단일 책임 원칙

- 어떤 클래스를 변경해야 하는 이유는 한가지 뿐이여야 한다.

각 클래스별로 응집도가 높고 독립적이어서, 필요시 다른 부분의 수정없이 그대로 가져다 사용가능해야함

각자 자신의 기능만 하도록!

package ch15;

public class Unit {

	private String name;
	private int speed;
	
	public void attack() {
	}
	
	public void move() {
	}
}

class Marin extends Unit{
	public void move() {
		this.speed+=3;
	}
}

class Tank extends Unit{
	public void move() {
		if("탱크모드") {
			speed = 0;
		}
		else {
			speed = 10;
		}
	}
}

class Race extends Unit{
	
	public void Race()
	{
		this.충돌 = false;
	}
	public void move() {
		speed = 15;
	}
}

위와같이 상속과 오버라이딩을 통해 단일책임원칙 구현

 

2. OCP (Open Closed Principle) 개방 폐쇄 원칙

내부적으로는 하나의 통로(폐쇄)

외부적으로는 여러개 (개방)

ex)

OCP 예제

3. LSP (Open Closed Principle) 개방 폐쇄 원칙

서브타입은 언제나 자신의 상위 타입으로 교체할 수 있어야 한다.

자식 -> 부모로 언제나 가능해야 한다.

ex) 아반떼 -> 소나타 / 소타나가 아반떼로 교체될 수는 없다. X

ex) 공중유닛 -> 정찰기 / 정찰기는 공중유닛으로 교체할 수 있다. O  

 

4. ISP (Interface Segregation Principle) 인터페이스 분리 원칙

*개발 방향에 따라 SRP (Single Responsibility Principle) 단일책임원칙 중 선택해서 적용

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

ex)

지도

도보안내()

지하철 노선()

자전거 내비()

 

자전거 내비 extends 지도 => X (도보안내, 지하철 노선 등 사용하지 않는 메서드들이 많음)

-> 자전거 내비를 분리해서 상속받아야함.

 

5. DIP (Dependency Inversion Principle)

자신보다 변하기 쉬운 것에 의존하지 말아야 한다.

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

ex) 사람 ->가을 옷 (추상 -> 구체)X

ex) 가을 옷 -> 옷 (구체 -> 추상)O


POJO JAVA

POFO JAVA란?

순수한 자바 오브젝트.

1. 특정  규약에  종속되지 않는다.

2. 특정 환경에 종속되지 않는다.

 

Spring, Hibernate

하나의 서비스의 개발을 위해,

시스템 복잡, 비지니스 로직의 복잡의 어려움이 있다

두 프레임워크는 객체지향적인 설계와 POJO를 지향하고 있다.

 

1. 자신의 코드에 if/else, switch가 난무하지 않는가?

2. 책임과 역할이 다른 코드가 하나의 클래스에 다 들어가 있지 않은가?

3. 절차지향적으로 한 개의 파일에 모든 코드를 넣고 있지 않는가?

4. 내가 만든 객체가 재사용이 가능한가?

돌아보자!!!!!!


디자인 패턴

자주 사용하는 설계 패턴을 정형화하여, 유형별로 최적의 방법으로 개발할 수 있도록 설계해놓은 형태

-Gof 디자인 패턴

(Gang of Four) 다양한 개발자의 지식을 공유하기 위해서 나온 것!

 

장점

-개발자간의 소통 쉬워짐

-구조 파악 용이

-재사용을 통한 시간 단축

 

단점

-기본적으로 객체지향적으로 설계되어 있어, 객체지향을 알아야함

-초기 투자비용이 든다

 

1. 생성패턴

-객체 생성 관련 패턴

-객체의 생성과 변경이 시스템에 미치는 영향 최소화시켜줌 -> 코드의 유연성 up

 

2. 구조패턴

-프로그램 내의 자료구조나 인터페이스 구조 등 구조 설계에 활동되는 패턴

-클래스, 객체들의 구성을 통해 더 큰 구조를 만들 수 있음

 

3. 행위패턴

-반복적으로 사용되는 객체들의 상호작용 패턴화

-클래스, 객체들의 상요작용 방법과 책임분산방법 제공


Singletin pattern

클래스의 객체가 유일하게 1개만 존재할 경우 사용

package com.company.design.singleton;

public class SocketClient {

    private static SocketClient socketClient = null;

    private SocketClient(){}
    // public SocketClient(){}

    public static SocketClient getInstance(){

        if(socketClient == null){
            socketClient = new SocketClient();
        }
        return  socketClient;
    }

    public void connect(){
        System.out.println("connect()");
    }

}

위와같이 private로 객체를 선언하여 외부에서 직접적인 생성을 못하도록 하는 구조.


Adapter Pattern

변환기, 어뎁터와 같은 구조

호완성이 없는 기존 클래스의 인터페이스를 변환하여 재사용 할 수 있게 해줌

package com.company.design.adapter;

public interface Electronic110V {

    void powerOn();
}
package com.company.design.adapter;

public interface Electronic220V {

    void connect();
}
package com.company.design.adapter;

public class SocketAdapter implements Electronic110V{

    private Electronic220V electronic220V;

    public SocketAdapter(Electronic220V electronic220V){
        this.electronic220V = electronic220V;
    }

    @Override
    public void powerOn() {
        electronic220V.connect();
    }
}

110V -> 220V로 변환하는 변압기 예제 코드이다.

    public static void connect(Electronic110V electronic110V){
        electronic110V.powerOn();
    }

아래와 같이, 110V를 받아, powerOn을 하는 클래스가 있다.

220V가 입력되기위해선 SockerAdapter 클래스의 Override를 통해 변환 해야한다.


Proxy Pattern

Proxy Class를 통해 대신 전달하는 형태

Cache 기능으로 활용 가능

package com.company.design.proxy;

public class BrowserProxy implements IBrowser{

    private String url;
    private Html html;

    public BrowserProxy(String url){
        this.url = url;
    }


    @Override
    public Html show() {

        if(html == null){
            this.html = new Html(url);
            System.out.println("BrowserProxy loading html form : "+url);
        }

        System.out.println("BrowserProxy use cache html : "+url);
        return  html;
    }
}

Browser Proxy를 통해 이미 로딩되었던 페이지라면, cache로 출력

package com.company.design.aop;

import com.company.design.proxy.Html;
import com.company.design.proxy.IBrowser;

public class AopBrowser implements IBrowser {

    private String url;
    private Html html;
    private Runnable before;
    private Runnable after;

    public AopBrowser(String url, Runnable before, Runnable after){
        this.url = url;
        this.before = before;
        this.after = after;
    }

    @Override
    public Html show() {
        before.run();

        if (html == null) {
            this.html = new Html(url);
            System.out.println("AopBrowser html loading from : "+url);
            try {
                Thread.sleep(1500);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        after.run();

        System.out.println("AopBrowser html cache : "+url);
        return html;
    }
}

AopBrowser을 통해 처음 로딩과 cache로딩의 시간차 생성하여 출력

출력 결과


Decorator Pattern

기본 뼈대가 있고, 이후 필요한 형태로 꾸밀 때 사용

아메리카노(뼈대) -> 카페라떼, 연유라떼 등

package com.company.design.decorator;

public class Audi implements ICar{

    private int price;

    public Audi(int price){
        this.price = price;
    }

    @Override
    public int getPrice() {
        return price;
    }

    @Override
    public void showPrice() {
        System.out.println("audi의 가격은 "+this.price+"원 입니다.");
    }
}
package com.company.design.decorator;

public class AudiDecorator implements ICar{

    protected ICar audi;
    protected String modelName;
    protected int modelPrice;

    public AudiDecorator(ICar audi, String modelName, int modelPrice){
        this.audi = audi;
        this.modelName = modelName;
        this.modelPrice = modelPrice;
    }

    @Override
    public int getPrice() {
        return audi.getPrice()+modelPrice;
    }

    @Override
    public void showPrice() {
        System.out.println(modelName+"의 가격은 "+getPrice()+"원 입니다.");
    }
}

AudiDecorator 클래스를 통해, 기본 Audi 클래스에서 모델별로 추가금액을 더해 알려준다.


Observer Pattern

관찰자 패턴, 변화에 따른 이벤트를 미리 등록된 다른 클레스에 통보해주는 패턴

ex) 망보는 친구가 다른 친구들에게 선생님 오시는거 말해준다.

package com.company.design.observer;

public class Button {

    private String name;
    private IButtonListener buttonListener;

    public Button(String name){
        this.name = name;
    }

    public void click(String message){
        buttonListener.clickEvent(message);
    }

    public void addListener(IButtonListener buttonListener){
        this.buttonListener = buttonListener;
    }
}
Button button = new Button("버튼");

        button.addListener(new IButtonListener() {
            @Override
            public void clickEvent(String event) {
                System.out.println(event);
            }
        });

        button.click("메시지 전달 : click1");
        button.click("메시지 전달 : click2");
        button.click("메시지 전달 : click3");
        button.click("메시지 전달 : click4");

Listener을 통해 버튼 클릭 이벤트를 전달해준다.


Facade Pattern

facade 건물의 앞쪽, 정면이라는 뜻

여러개의 객체와, 서브 객체 사이의 복잡한 의존관계가 있을 시, facade 객체를 두고 interface만을 활용하여 기능을 사용하는 방식

Ftp ftpClient = new Ftp("www.foo.co.kr",22,"/home/etc");
        ftpClient.connect();
        ftpClient.moveDirectory();

        Writer writer = new Writer("text.tmp");
        writer.fileConnect();
        writer.write();

        Reader reader = new Reader("text.tmp");
        reader.fileConnect();
        reader.fileRead();

        reader.fileDisconnect();
        writer.fileDisconnect();
        ftpClient.disConnect();

        //위의 복잡성을 단순하게 해줌
        SftpClient sftpClient = new SftpClient("www.foo.co.kr",22,"/home/etc","text.tmp");
        sftpClient.connect();

        sftpClient.writer();

        sftpClient.read();

        sftpClient.disConnect();

위의 복잡한 writer, reader, ftp를 facade를 통해 단순하게 구현

아래는 SftpClient클래스

package com.company.design.facade;

public class SftpClient {
    private  Ftp ftp;
    private Reader reader;
    private Writer writer;

    public SftpClient(Ftp ftp, Reader reader, Writer writer){
        this.ftp = ftp;
        this.reader = reader;
        this.writer = writer;
    }

    public SftpClient(String host, int port, String path, String fileName){
        this.ftp = new Ftp(host, port, path);
        this.reader = new Reader(fileName);
        this.writer = new Writer(fileName);
    }

    public void connect(){
        ftp.connect();
        ftp.moveDirectory();
        writer.fileDisconnect();
        reader.fileConnect();
    }

    public void disConnect(){
        writer.fileDisconnect();
        reader.fileDisconnect();
        ftp.disConnect();
    }

    public void read(){
        reader.fileRead();
    }

    public void writer(){
        writer.write();
    }
}

Strategy Pattern

전략패턴, 유사한 행위들을 캡슐화하여, 객체의 행위를 바꾸고 싶은 경우 전략만 변경. 유연하게 확장하는 패턴

-전략 메서드를 가진 전략 객체

-전략 객체를 사용하는 컨텍스트

-전략 객체를 생성해 컨텍스트에 주입하는 클라이언트

위의 3개가 필수요소!

Encoder encoder = new Encoder();
        //base64
        EncodingStrategy base64 = new Base64Strategy();
        //normal
        EncodingStrategy normal = new NormalStrategy();

        String message = "hello java";

        encoder.setEncodingStrategy(base64);
        String base64Result = encoder.getMessage(message);
        System.out.println(base64Result);

        encoder.setEncodingStrategy(normal);
        String normalResult = encoder.getMessage(message);
        System.out.println(normalResult);

        encoder.setEncodingStrategy(new AppendStrategy());
        String appendResult = encoder.getMessage(message);
        System.out.println(appendResult);
반응형