네로개발일기

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

'dev book/스프링 입문을 위한 자바 객체 지향의 원리와 이해'에 해당되는 글 5건


반응형

스프링을 이해하려면 POJO 기반으로 스프링 삼각형이라는 애칭을 가진 IoC/DI, AOP, PSA라고 하는 스프링의 3대 프로그래밍 모델에 대해 이해가 필수다.

 

IoC/DI - 제어의 역전/의존성 주입

프로그래밍에서 의존성이란 무엇일까?

예를들어) 운전자가 자동차를 생성한다. -> 자동차가 내부적으로 타이어를 생산한다. (운전자 -> 자동차 -> 타이어) 의존

-> 전체(의존하는 객체)가 부분(의존되는 객체)에 의존한다.

 

집합(Aggregation) 관계: 부분이 전체와 다른 생명 주기를 가질 수 있다.

구성(Composition) 관계: 부분은 전체와 같은 생명 주기를 갖는다.

interface Tire {
    String getBrand();
}

public class KoreaTire implements Tire {
    public String getBrand() {
        return "한국 타이어";
    }
}

public class AmericaTire implements Tire {
    public String getBrand() {
        return "미국 타이어";
    }
}

public class Car {
    
    Tire tire;
    
    public Car() {
        tire = new KoreaTire(); // Car 클래스는 Tire 인터페이스 뿐만 아니라 KoreaTire 클래스도 의존하게 된다.
    }
    
    public String getTireBrand() {
        return "장착된 타이어: " + tire.getBrand();
    }

 

1. 생성자 주입

public class Car {
    Tire tire;
    
    public Car(Tire tire) { // 생성자 주입
        this.tire = tire;
    }
    
    public String getTireBrand() {
        return "장착된 타이어: " + tire.getBrand();
    }
}

public class Driver {
    public static void main(String[] args) {
        Tire tire = new KoreaTire();
        
        Car car = new Car(tire);
        
        System.out.println(car.getTireBrand());
    }
}

의존성 주입을 이용함으로써 자동차가 구체적인 객체를 생성하고 연결하는 것이 아니라 운전자가 대신 원하는 의존성을 생성하고 연결해준다.

 

따라서, Car 객체는 의존성 주입을 통해 추상적인 인터페이스에 의존하면서 실행이 가능해진다. Car 객체는 수정없이 확장이 가능해진다.

 

생성자 주입 방식의 장점

- 의존 관계 설정이 되지 않으면 객체 생성 불가 -> 컴파일 타임에 인지 가능 NPE 방지

- 의존성 주입이  필요한 필드를 final로 선언하여 Immutable한 객체로 만들 수 있음

- 순환 참조 감지 기능 -> 순환 참조시 앱 구동 실패

- 테스트 코드 작성 용이 (독립적으로 인스턴스화가 가능한 POJO(Plain Old Java Object)여야 하는 것이다. DI 컨테이너를 사용하지 않고도 단위 테스트에서 인스턴스화할 수 있어야 한다.)

 

2. 속성 주입

@Autowired를 통한 의존성 주입

@Autowired Tire tire를 사용하여 설정자 메서드를 사용하지 않고도 스프링 프레임워크가 설정파일을 통해 설정자 메서드 대신 속성을 주입해준다.

 

@Resource를 통한 속성 주입

@Resource는 @Autowired와 같이 속성을 자동으로 엮어준다. @Autowired는 스프링의 어노테이션이고 @Resource는 자바표준 어노테이션이다.  

 

AOP - Aspect 관점 핵심 관심사 횡단 관심사

AOP - 관점지향 프로그래밍

스프링 DI가 의존성에 대한 주입이라면 AOP는 로직에 대한 주입이다.

 

여러 모듈에서 발생하는 공통적인 부분 -> 횡단 관심사

AOP 로직 주입이 가능한 부분

Around(메서드 전 구역), Before(메서드 시작 전), After(메서드 종료 후), After Returning(메서드 정상 종료 후), After Throwing (메서드에서 예외가 발생하면서 종료된 후)

 

스프링 AOP의 핵심

- 인터페이스 기반

- 프록시 기반

- 런타임 기반

 

PSA - 일관성 있는 추상화

서비스 추상화의 예로 JDBC를 들 수 있다. JDBC라고 하는 표준 스펙이 있기에 어떤 DBMS를 사용하든 Connection, Statement, ResultSet을 이용해 공통된 방식으로 코드 작성이 가능하다. 데이터베이스의 종류에 관계없이 같은 방식으로 제어할 수 있는 이유는 디자인패턴에서 설명했던 어댑터패턴을 활용했기 때문이다.

 

다수의 기술을 공통의 인터페이스로 제어할 수 있게 한 것 -> 서비스 추상화

스프링 프레임워크는 서비스 추상화를 위해 다양한 어댑터를 제공한다.

728x90
반응형
blog image

Written by ner.o

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

반응형

'객체지향의 4대 특성'은 객체지향을 잘 사용하기 위한 도구이다.

'객체지향의 5대 원칙'은 이러한 도구를 올바르게 사용하는 원칙으로 볼 수 있다.

'디자인 패턴'은 레시피에 비유할 수 있다.

실제 개발현장에서 비즈니스 요구사항을 처리하면서 만들어진 다양한 해결책 중 많은 사람들이 인정한 Best Practice를 정리한 것이다.

-> 스프링 역시 다양한 디자인 패턴을 활용하고 있다.

스프링 공식 정의: "자바 엔터프라이즈 개발을 편하게 해주는 오픈소스 경량급 애플리케이션 프레임워크"

디자인 패턴은 객체 지향의 특성 중 '상속', '인터페이스', '합성'을 이용한다. (합성은 객체를 속성으로 사용하는 것)

 

어댑터 패턴 (Adapter Pattern)

한 클래스의 인터페이스를 클라이언트에서 사용하고자 하는 다른 인터페이스로 변환한다.
어댑터를 이용하면 인터페이스 호환성 문제 때문에 같이 쓸 수 없는 클래스들을 연결해서 쓸 수 있다.

OBDC/JDBC가 어댑터 패턴을 이용해 다양한 데이터베이스 시스템을 단일한 인터페이스로 조작할 수 있게 해준다.

'어플리케이션' - '어댑터' - '실제 구현체'

 

어댑터 패턴 사용

public class AdapterServiceA {
    ServiceA serviceA = new ServiceA();
    
    void runService() {
        serviceA.runServiceA();
    }
}

public class AdapterServiceB {
    ServiceB serviceB = new ServiceB();
    
    void runService() {
        serviceB.runServiceB();
    }
}

// 어댑터 패턴이 적용된 코드
public class ClientWithAdapter {
    public static void main(String[] args) {
        AdapterServiceA adpaterA = new AdapterServiceA();
        AdapterServiceB adpaterB = new AdapterServiceB();
        
        adpaterA.runService();
        adpaterB.runService()
    }
}

어댑터에서 동일한 이름의 runService()를 사용해서 각각의 runServiceX를 호출하고 있다.

어댑터가 특정 인터페이스를 구현하게 해서 하나의 인터페이스에서 의존관계 주입을 통해 똑같은 메서드로 각각 다른 구현체의 메서드를 호출할 수 있다.

호출당하는 쪽의 메서드를 호출하는 쪽의 코드에 대응하도록 중간에 변환기를 통해 호출하는 패턴

 

프록시 패턴 (Proxy Pattern)

프록시는 대리자라는 의미이다. 다른 누군가를 대신해 그 역할을 수행하는 존재를 말한다.

 

프록시 패턴 사용

public interface IService {
    String runSomething();
}

public class Service implements IService {
    public String runSomething() {
        return "서비스 최고!!";
    }
}

public class Proxy implements IService {
    IService service;
    
    public String runSomething() {
        System.out.println("호출에 대한 흐름 제어가 주 목적, 변환 결과를 그대로 전달");
        
        service = new Service();
        return service.runSomething();
    }
}

public class ClientWithProxy {
    public static void main(String[] args) {
        IService proxy = new Proxy();
        System.out.println(proxy.runSomething());
    }
}

서비스 객체가 들어갈 자리에 대리자 객체를 대신 투입한다.

 

  • 프록시는 실제 서비스와 같은 이름의 메서드를 구현
  • 프록시는 실제 서비스에 대한 참조 변수를 갖는다. (합성)
  • 프록시는 실제 서비스의 메서드와 같은 이름을 가진 메서드를 호출하고 그 값을 클라이언트에게 반환한다.
  • 프록스는 실제 서비스의 메서드 호출 전후에 별도의 로직을 수행할 수 있다.
프록시 패턴은 실제 서비스의 반환값은 변경하지 않고 제어의 흐름을 변경하거나 다른 로직을 수행하기 위해 사용한다.

 

데코레이터 패턴 (Decorator Pattern)

원본에 장식을 더하는 패턴

프록시 패턴과 구현 방법이 같으나 최종적으로 반환값에 장식을 덧입힌다.

public class Decorator implements IService {

    IService service;
    
    public String runSomething() {
        System.out.println("호출에 대한 장식 주목적, 클라이언트에게 반환 결과에 장식을 더하여 전달");
        
        service = new Service();
        
        return "정말" + service.runSomething(); // 반환값에 다른 값을 추가한다.
    }
}

데코레이터 패턴의 중요 포인트는 프록시 패턴의 중요 포인트에 반환값에 변화를 줄 수 있다는 점이다.

 

싱글톤 패턴 (Singleton Pattern)

인스턴스를 하나만 만들어 사용하기 위한 패턴

'커넥션 풀', '스레드 풀', '디바이스 설정 객체' 등과 같은 경우 인스턴스를 여러 개 만들게 되면 불필요한 자원을 사용하게 되고, 프로그램이 예상하지 못한 결과를 만들 수 있다.

 

싱글톤 패턴을 적용하면 두 개의 객체가 존재할 수 없으므로 

1. 객체 생성을 위한 new에 제약을 걸어야 하고

2. 만들어진 단일 객체를 반환할 수 있는 메서드가 필요하다.

 

  • new 를 사용할 수 없도록 생성자에 private 접근 제어자를 설정한다.
  • 유일한 단일 객체를 반환할 수 있는 정적 메서드가 필요하다.
  • 유일한 단일 객체를 참조할 정적 참조 변수가 필요하다.
public class Singleton {
    static Singleton singletonObject; // 정적 참조 변수
    
    // private 생성자
    private Singleton {
    }
    
    // 객체 변환 정적 메서드
    public static Singleton getInstance() {
        if (singletonObject == null) {
            singletonObject = new Singleton();
        }
        
        return singletonObject;
    }
}

 

 

템플릿 메서드 패턴 (Template Method Pattern)

상위 클래스의  견본 메서드에서 하위 클래스가 오버라이딩한 메서드를 호출하는 패턴

공통적으로 사용하는 메서드는 상위 클래스에서 구현

하위 클래스마다 달라지는 것은 추상 클래스로 구현 강제화

하위 클래스마다 달라질 수 있는 것은 오버라이드 가능한 훅 메서드로 만듦.

 

public abstract class Animal {

    // 템플릿 메서드
    public void playWithOwner() {
        System.out.println("귀염둥이 이리온...");
        play();
        runSomething();
        System.out.println("잘했어!");
    }
    
    // 추상 메서드
    abstract void play();
    
    // Hook(갈고리) 메서드
    void runSomething() {
        System.out.println("꼬리 살랑 살랑-");
    }
}

상위 클래스에서 템플릿을 제공하는 playWithOwner() 템플릿 메서드를 제공한다.

그리고 템플릿 메서드 안에 있는 play() 추상 메서드와 runSomething() 메서드가 있다.

-> 추상 메서드는 하위 클래스에서 구현을 강제한다.

-> Hook 메서드는 오버라이드가 자유롭다.

 

템플릿 메서드: 공통 로직 수행, 로직 수행 중 추상메서드 혹은 훅 메서드를 호출

템플릿 메서드에서 호출하는 추상 메서드: 반드시 하위 클래스가 오버라이딩 해야 한다.

템플릿 메서드에서 호출하는 훅 메서드: 하위 클래스가 선택적으로 오버라이딩한다.

 

팩터리 메서드 패턴 (Factory Method Pattern)

오버라이드된 메서드가 객체를 반환하는 패턴

팩터리 메서드는 객체를 생성/반환하는 메서드를 말한다.

팩터리 메서드 패턴은 하위 클래스에서 팩터리 메서드를 오버라이딩해서 객체를 반환하는 것을 의미한다.

// 추상 팩터리 메서드
public abstract class Animal {

    // 추상 팩터리 메서드
    abstract AnimalToy getToy();
}

// 추상 팩터리 메서드 오버라이딩
public class Dog extends Animal {

    @Override
    AnimalToy getToy() {
        return new DogToy();
    }
}

public class Driver {
    public static void main(String[] args) {
        Animal bolt = new Dog();
        Animal kitty = new Cat();
        
        AnimalToy boltBall = bolt.getToy();
        AnimalToy kittyTower = kitty.getToy();
        
        boltBall.identify();
        kittyTower.identify();
    }
}

전략 패턴 (Strategy Pattern)

클라이언트가 전략을 생성해 전략을 실행할 컨텍스트에 주입하는 패턴

전략 패턴 구성요소 3가지

  • 전략 메서드를 가진 전략 객체
  • 전략 객체를 사용하는 컨텍스트 (전략 객체의 사용자/소비자)
  • 전략 객체를 생성해 컨텍스트에 주입하는 클라이언트 (전략 객체의 공급자)
// 전략 인터페이스
public interface Strategy {
    public abstract void runStrategy();
}

// 전략 인터페이스 구현
public class StrategyGun implements Strategy {
    
    @Override
    public void runStrategy() {
        System.out.println("탕, 타당, 타다당");
    }
}
public class StrategySword implements Strategy {
    
    @Override
    public void runStrategy() {
        System.out.println("챙! 챙챙! 챙챙챙!");
    }
}

// 전략을 사용하는 컨텍스트
public class Soldier {
    void runContext(Strategy strategy) {
        System.out.println("전투 시작!");
        strategy.runStrategy();
        System.out.println("전투 종료!");
    }
}

// 전략 패턴의 클라이언트
public class Client {
    public static void main(String[] args) {
        Strategy strategy = null;
        Soldier rambo = new Soldier();
        
        strategy = new StrategyGun();
        rambo.runContext(strategy);
        
        strategy = new StrategySword();
        rambo.runContext(strategy);
                
    }
}

클라이언트는 전략을 다양하게 변경하면서 컨텍스트를 실행할 수 있다.

 

전략 패턴에는 OCP, DIP가 적용된다.

 

템플릿 콜백 패턴 (Template Callback Pattern)

전략을 익명 내부 클래스로 구현한 전략 패턴

템플릿 콜백 패턴은 전략 패턴의 변형으로 스프링 3대 프로그래밍 모델 중 하나인 DI에서 사용하는 특별한 형태의 전략 패턴이다.

전략 패턴과 동일하지만 전략을 익명 내부 클래스로 정의해서 사용한다.

 

public class Client {
	public static void main(String[] args) {
		Soldier rambo = new Soldier();

		rambo.runContext(new Strategy() {
			@Override
			public void runStrategy() {
				System.out.println("총! 총초종총 총! 총!");
			}
		});

		System.out.println();

		rambo.runContext(new Strategy() {
			@Override
			public void runStrategy() {
				System.out.println("칼! 카가갈 칼! 칼!");
			}
		});

		System.out.println();

		rambo.runContext(new Strategy() {
			@Override
			public void runStrategy() {
				System.out.println("도끼! 독독..도도독 독끼!");
			}
		});
	}
}

 

위 코드는 중복이 있으므로 리팩토링이 가능하다.

public class Soldier {

    void runContext(String weaponSound) {
        System.out.println("전투 시작");
        executeWeapon(weaponSound).runStrategy();
        System.out.println("전투 종료");
    }
    
    private Strategy executeWeapon(final String weaponSound) {
        return new Strategy() {
            @Override
            public void runStrategy() {
                System.out.println(weaponSound);
            }
        };
    }
}

public class Client {
    public static void main(String[] args) {
        Soldier rambo = new Soldier();
        
        rambo.runContext("총! 총초종총 총! 총!");
        System.out.println();
        
        rambo.runContext("칼! 카가갈 칼! 칼!");
        System.out.println();
        
        rambo.runContext("도끼! 독독..도도독 독끼!");
    }
}

중복되는 전략을 생성하는 코드가 컨텍스트 내부로 들어왔다. (중복되는 부분을 컨텍스트로 이관)

 

스프링은 이런식으로 리팩터링된 템플릿 콜백 패턴을 DI에 적극 활용하고 있다.

OCP, DIP 적용된 설계 패턴이다.

 

 

728x90
반응형
blog image

Written by ner.o

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

반응형

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

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