728x90

/* 이 글은 김영한님의 강의를 보고 정리하려고 작성한 글입니다. */

 

 

 

SOLID

 

* 클린코드로 유명한 로버트 마틴이 좋은 객체 지향 설계의 5가지 원칙을 정리

 

- SRP : 단일 책임 원칙 (Single Responsibility Principle)

- OCP : 개방-폐쇄 원칙 (Open / Closed Principle)

- LSP : 리스코프 치환 원칙 (Liskov Substitution Principle)

- ISP : 인터페이스 분리 원칙 (Interface Segregation Principle)

- DIP : 의존관계 역전 원칙 (Dependency Inversion Principe)

 

 

 

 

1. SRP (단일 책임 원칙)

 

  한 클래스는 하나의 책임만 가져야 한다.

(여기서 하나의 책임이라는 것은 모호하기 때문에 범위의 단위를 적절히 잘 조절해야함.)

➔   클래스가 데이터베이스 연결, 비즈니스 로직, 사용자 인터페이스 처리 등 다양한 책임을
가지고 있다면 이것은 SRP를 위반했다고 볼 수 있다.

 

  중요한 기준은 변경이다. 변경이 있을 때 파급 효과가 적으면 단일 책임 원칙을 잘 따른 것 

ex ) UI변경, 객체의 생성과 사용을 분리

➔ 특정 책임만 가질 경우 변경하거나 디버깅 하는 것이 쉬워지며 유지보수성을 향상시킴

 

 

 

 

2. OCP (개방-폐쇄 원칙)

 

  소프트웨어 요소는 확장에는 열려 있으나 변경에는 닫혀 있어야 한다.

➔ 이게 무슨 말인지 처음에 헷갈렸는데..
 기존의 코드를 수정하지 않고도 새로운 기능을 추가하거나 변경할 수 있어야 한다.

 

  아래의 예시처럼 인터페이스와 다형성을 사용하여 역할과 구현을 분리해야 한다.

   역할과 구현의 분리 예시

 새로운 클래스를 만들어 이미 정의된 인터페이스를 구현하거나 상속받아 새로운 기능을 구현

➔ 오버라이딩 하여 메서드를 재정의 하는 방법

 

 

 

 

3. LSP (리스코프 치환 원칙)

 

  프로그램의 객체는 프로그램의 정확성을 깨뜨리지 않으면서 하위 타입의 인스턴스로 바꿀 수 있어야 한다.

 

  다형성에서 하위클래스는 인터페이스 규약을 다 지켜야 한다는 것

 

   다형성을 지원하기 위한 원칙, 인터페이스를 구현한 구현체를 믿고 사용하려면 이 원칙이 필요하다.

 

  단순히 컴파일에 성공하는 것을 넘어서는 이야기

 

   ex ) 자동차 인터페이스의 엑셀은 앞으로 가는 기능 일 때, 여기에 뒤로 가는 기능으로 만들 수도 있고 그렇게 하더라                   도 컴파일 오류가 나진 않음. 그러나 LSP원칙은 컴파일 단계를 얘기하는것이 아님.

   인터페이스의 엑셀 규약은 무조건 앞으로 가야되기 때문에 그 기능에 대해 보장을 해줘야 함.

➔ 뒤로 간다면 LSP원칙 위반

 

 

 

 

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

 

  특정 클라이언트를 위한 인터페이스 여러 개가 범용 인터페이스 하나보다 낫다.

   ex ) 자동자 인터페이스 : 운전 인터페이스, 정비 인터페이스로 분리

               사용자 클라이언트 :  운전자 클라이언트, 정비사 클라이언트로 분리

 

   이렇게 분리 했을 때 정비와 관련된 기능을 바꿀 경우 정비 인터페이스와 정비사 인터페이스만 바꾸면 됨.

 운전자 클라이언트에 영향을 주지 않음 !

 

  인터페이스가 명확해지고, 대체 가능성이 높아진다.

 

 

 

 

5. DIP (의존관계 역전 원칙)

 

  프로그래머는 "추상화에 의존해야지, 구체화에 의존하면 안된다"의 원칙을 따르는 방법 중 하나

➔ 구현 클래스에 의존하지말고, 인터페이스에 의존하라는 뜻 = 역할에 의존해야 한다.

 

 원빈(=구현체)이 김태희(=구현체)랑만 공연 연습을 했다고해서 송혜교(=구현체)랑 공연하기 힘들면 안됨. 원빈은 로미오(=인터페이스) 역할에만 의존해야 함

상대배우(=구현체)에 의존하지 말고 자신의 대본(=역할, 인터페이스)에 의존해서 언제든지 다른 배우와 공연이 가능하도록 역할과 구현을 철저하게 분리해야 함.

 

 

 

 

결론

 

  객체 지향의 핵심은 다형성

But, 다형성 만으로는 쉽게 부품을 갈아 끼우듯 개발할 수 없다.

(다형성 만으로는 구현 객체를 변경할 때 클라이언트 코드도 함께 변경된다.)

 

  다형성 만으로는 OCP, DIP를 지킬 수 없다.

하지만 스프링을  사용한다면 이것들을 지킬 수 있게 된다.

 

 

 

 

다시 스프링으로

 

  스프링은 다음기술로 다형성 + OCP, DIP를 가능하게 지원

- DI(Dependency Injection) : 의존관계, 의존성 주입

- DI 컨테이너 제공 = IOC

 

  클라이언트 코드의 변경 없이 기능 확장

 

  쉽게 부품을 교체하듯이 개발

 

 

 

 

정리

 

  모든 설계에 역할 구현 분리하자.

ex ) 위에 나왔던 공연의 예시처럼 배역만 만들어두고 배우는 언제든지 유연하게 변경할 수 있도록 설계

 

  이상적으로는 모든 설계에 인터페이스를 부여하자

(인터페이스를 먼저 설계하고 구현을 나중에 정하게 되면 구현 기술이 바뀌더라도 변경 범위가 작고 유연해짐.)

But, 인터페이스를 도입하면 추상화라는 비용이 발생함.

 기능을 확장할 가능성이 없다면 구체 클래스를 직접 사용하고, 향후 꼭 필요할 때 리팩터링해서 도입하는 것도 방법.

 

  ◾  프로그램의 객체는 프로그램의 정확성을 깨뜨리지 않으면서 하위 타입의 인스턴스로 바꿀 수 있어야 한다.

 

  ◾  다형성에서 하위클래스는 인터페이스 규약을 다 지켜야 한다는 것, 다형성을 지원하기 위한 원칙, 인터페이스를 구현한 구현체는 믿고 사용하려면 이 원칙이 필요하다.

 

  ◾  단순히 컴파일에 성공하는 것을 넘어서는 이야기

ex ) 자동차 인터페이스의 엑셀은 앞으로 가는 기능 일 때, 여기에 뒤로 가는 기능으로 만들 수도 있고 그렇게 하더라도 컴파일 오류가 나진 않음. 그러나 LSP원칙은 컴파일 단계를 얘기하는것이 아님.

인터페이스의 엑셀 규약은 무조건 앞으로 가야되기 때문에 그 기능에 대해 보장을 해줘야 함.

➔ 뒤로 간다면 LSP원칙 위반

728x90
728x90

JOIN

  • JOIN 이란 - 하나 이상의 테이블로부터 연관된 데이터를 검색해 오는 방법

Cartesian Join

  • Join에 대한 조건이 생략되거나 잘못 기술되어 한 테이블에 있는 모든 행들이 다른 테이블에 있는 모든 행들과 Join이 되어서 얻어진 경우를 Cartesian Product라 한다.
  • 두 테이블의 합집합이라 생각하면 된다.
  • select * from employees, departments;
  • Cartesian Product를 얻지 않기 위해서 반드시 WHERE 절을 써 준다.
  • (JOIN 하는 테이블의 수 - 1) 개의 JOIN 조건이 필요하다.

Simple Join

SELECT t1.col1, t1.col2, t2.col1 ... FROM Table1 t1, Table2 t2
WHERE t1.col3 = t2.col3
  • FROM 절에 필요로 하는 테이블을 모두 적는다.
    • 컬럼 이름의 모호성을 피하기 위해 테이블 이름으로 직접 지칭 가능 (어느 테이블에 속하는지 알 수 없는 경우가 있을 수 있으므로 Table 이름에 Alias 사용)
    • 적절한 Join 조건을 Where 절에 부여 (일반적으로 테이블 개수 -1 개의 조인 조건이 필요)
    • 일반적으로 PK와 FK간의 = 조건 이 붙는 경우가 많다.

Join 종류

종류 설명

Cross Join (Cartesian Product) 모든 가능한 쌍이 나타남
Inner Join 조건을 만족하는 튜플만 나타남
Outer Join Join 조건을 만족하지 않는 튜플 (짝이 없는 튜플)도 null과 함께 나타남
Theta Join 조건(theta) 에 의한 조인 / (FK가 아닌 다른걸 이용 ?)
Equi-Join Theta Join & 조건이 Equal (=)
Natural Join Equi-Join & 동일한 Column 명 합쳐짐
Self Join 자기 자신과 조인

EQUI-JOIN

  • 컬럼에 있는 값이 정확하게 일치하는 경우에 = 연산자를 사용하여 JOIN
SELECT 테이블명.컬럼명, 테이블명.컬럼명. …
FROM 테이블1, 테이블2
WHERE 테이블1.컬럼1 = 테이블2.컬럼2
  • 테이블명.컬럼명 - 검색해올 데이터가 어디에서 오는지 테이블과 컬럼을 밝혀둔다.
  • 테이블1.칼럼1 = 테이블2.컬럼2 - 두 테이블 간에 논리적으로 값을 연결시키는 칼럼 간의 조건을 기술한다.

EQUI-JOIN의 문형

  • 컬럼에 있는 값들이 정확히 일치하는 경우에 = 연산자를 사용해서 조인
  • 일반적으로 PK-FK 관계에 의하여 JOIN이 성립
  • WHERE절 or ON절을 이용
  • 액세스 효율을 향상시키고 좀 더 명확히 하기 위해 칼럼이름 앞에 테이블 이름을 밝힌다.
  • 같은 이름의 칼럼이 조인대상 테이블에 존재하면 반드시 테이블 이름을 밝혀줄 것 !
  • JOIN을 위한 테이블이 N개라 하면, JOIN을 위한 최소한의 = 조건은 N-1 이다.
# 사원 이름과 부서명을 출력하라.
select emp.ename, dept.dname from emp, dept;
select e.ename, d.dname from emp e, dept d;
select ename, dname from emp e, dept d;

# 중복되는 컬럼명 앞에는 반드시 테이블을 명시해야함
select ename, dname, e.deptno from emp e, dept d;

select e.ename, d.dname from emp e, dept d
where e.deptno = d.deptno;

# 모든 사원의 사번, first_name, email, department_name을 조회하라
select e.employee_id, e.first_name, e.email, d.department_name
from employees e, departments d
where e.department_id = d.department_id;

추가적인 조건 기술

  • WHERE 절에 JOIN 조건 이외의 추가적인 조건을 가질 수 있다.
  • 조인을 만족하는 데이터 중 특정 행만 선택하여 결과를 얻고 싶을 때 추가조건을 AND로 연결한다.
  • 사원의 이름과 부서명을 출력하라. 단, location_id 가 1800인 경우만 출력하라.
  • select concat(e.first_name, ' ', e.last_name) as 이름, d.department_name, l.city from employees e, departments d, locations l where e.department_id = d.department_id and d.location_id = l.location_id and l.location_id = 1800;

조건(theta) Join

  • 임의의 조건을 Join 조건으로 사용가능
  • Non-Equi Join 이라고도 한다.
  • # 이름, 급여, 등급을 조회하라 select e.ename, e.sal, s.grade from emp e, SALGRADE s where e.sal BETWEEN s.LOSAL AND s.HISAL;

Natural Join

  • 두 테이블에 공통 칼럼이 있는 경우 별다른 조인 조건없이 공통 칼럼처럼 묵시적으로 조인이 되는 유형
  • ANSI / ISO SQL1999를 따르는 ANSI JOIN 문법
select e.ename, d.dname
from emp e natural join dept d;

문제점

  • 조인하고자 하는 두 테이블에 같은 이름의 칼럼이 많을 때, 위와 같을 시 특정한 칼럼으로만 조인하고 싶다면 USING 절을 사용해서 기술한다.
  • select e.ename, d.dname from emp e join dept d using(deptno);

INNER JOIN - JOIN ~ ON

  • 공통된 이름의 칼럼이 없는 경우 가장 보편적으로 사용할 수 있는 유형이다.
  • WHERE 절에 일반조건만 쓸 수 있게하고, 조인 조건은 ON에 두어 보다 의미를 명확히 하고 알아보기도 쉽다.
  • ON 부분을 WHERE 절에서 작성 가능하다.
  • select e.ename, d.dname from emp e join dept d on (e.deptno = d.deptno) where d.deptno = 20 ;

Outer Join

  • Join 조건을 만족하지 않는(짝이 없는) 튜플의 경우 Null을 포함하여 결과를 생성
  • 모든 행이 결과 테이블에 참여

종류

  • Left Outer Join - 왼쪽의 모든 튜플은 결과 테이블에 나타남
  • Right Outer Join - 오른쪽의 모든 튜플은 “”
  • Full Outer Join - 양쪽 모두 결과 테이블에 참여

→ 왼쪽 테이블의 Null 값을 포함하는 튜플도 모두 보고 싶어요 : Left Outer Join

  • 오라클의 경우, NULL이 올 수 있는 쪽 조건에 + 를 붙여준다.
select e.ename, d.dname
from emp e left outer join dept d using(deptno); # 왼쪽의 모든 튜플

select e.ename, d.dname
from emp e right outer join dept d using(deptno); # 오른쪽의 모든 튜플

select e.ename, d.dname
from emp e left outer join dept d using(deptno)
union
select e.ename, d.dname
from emp e right outer join dept d using(deptno); # 양쪽 모든 튜플
  • MySQL의 경우, FULL OUTER JOIN이 아닌 UNION 연산을 통해 가능하다.

JOIN 문법 정리

SELECT table1.column, table2.column
FROM table1

[CROSS JOIN table2] |

[NATURAL JOIN table2] |

[JOIN table2 USING (column_name)] |

[JOIN table2
ON(table1.column_name = table2.column_name)] | [LEFT|RIGHT|FULL OUTER JOIN table2
ON (table1.column_name = table2.column_name)];
  • left outer → left / right outer → right 로 축약해서 사용가능

SELF JOIN

  • 하나의 테이블을 서로 다른 테이블로 생각하여 JOIN 하는 것
# 사원이름과 매니저 이름을 출력하라.
select e.ename 사원명, m.ename 매니저이름
from emp e, emp m
where e.mgr = m.empno;

# 사원이름, 매니저 이름을 출력하세요. 단, 매니저가 없는 사원도 출력하시오.
select e.ename 사원명, m.ename 매니저이름
from emp e
left outer join emp m
on e.mgr = m.empno;

🔎 SubQuery

  • 하나의 SQL 질의문 속에 다른 SQL 질의문이 포함되어 있는 형태
  • 쿼리 하나로는 원하는 결과를 얻어내지 못하는 경우에 사용
# SMITH가 속한 부서의 급여 평균을 알고 싶다.
# 1. 스미스의 부서 번호는?
# 2. 해당 부서 번호의 급여 평균

select avg(sal)
from emp
where deptno = (select deptno from emp where ename = 'SMITH');
  • ✔ 서브쿼리 짜는 것을 익히기 위해선 각 조건들을 작은 단위로 (쿼리 하나씩) 뽑아내는 연습을 하는 것이 좋겠다.

Single-Row Subquery

  • Subquery의 결과가 한 개의 ROW인 경우
  • Single-Row Operator 를 사용해야 함 - = , > , >= , < , <= , <>
# 사원의 평균 급여보다 작은 급여를 받는 사원의 이름과 급여를 출력
select ename, sal
from emp
where sal < (select avg(sal)
             from emp);

# 부서이름이 SALES인 부서의 사원 이름과 부서 번호를 출력
select ename, deptno
from emp
where deptno = (select deptno
                from dept
                where dname = 'SALES');

Multi-Row SubQuery (Feat. IN, ANY, ALL)

  • Subquery의 결과가 둘 이상의 ROW
  • Multi-Row에 대한 연산을 사용해야 함 - ANY , ALL , IN , EXIST …
# 아래의 경우는 오류가 발생한다.
SELECT *
FROM emp
WHERE ename = (SELECT MIN(ename)
               FROM emp GROUP BY deptno);

# 아래와 같이 in 연산을 사용하여 그룹 내에 있는지
# 확인하는 식으로 사용해야 한다.
SELECT *
FROM emp
WHERE ename in ('KANG', 'CLARK', 'ADAMS', 'ALLEN');

# 따라서 다음과 같이 해결할 수 있다.
SELECT *
FROM emp
WHERE ename in (SELECT MIN(ename)
               FROM emp GROUP BY deptno);

ANY

  • 다수의 비교값 중 한개라도 만족하면 true
  • IN 과 다른 점은 비교 연산자를 사용한다는 점
  • SELECT ename, sal, deptno FROM emp WHERE ename = ANY (SELECT MIN(ename) FROM emp GROUP BY deptno); # 아래 쿼리는 sal > 950 과 같은 결과이다. SELECT * FROM emp WHERE sal > ANY(950, 3000, 1250)

ALL

  • 전체 값을 비교해서 모두 만족해야만 true
  • Oracle은 오류가 발생하지 않지만, MySQL은 Subquery에서만 사용 가능하다.
  • # 아래의 쿼리는 결과가 없다. 모두를 만족할 수는 없기 때문 # MySQL에서는 값에 대해서는 ALL을 사용할 수 없다. 여기선 단지 예제일뿐 ! SELECT * FROM emp WHERE sal = ALL(950, 3000, 1250) # 결국 아래와 같이 사용된다. select * from emp where sal < all (select sal from emp where deptno in (30, 10));

Correlated Query

  • Outer Query와 Inner Query가 서로 연관되어 있다.
  • 해석방법
    • Outer query의 한 Row를 얻는다.
    • 해당 Row를 가지고 Inner Query를 계산한다.
    • 계산 결과를 이용, Outer query의 WHERE 절을 evaluate
    • 결과가 참이면 해당 Row를 결과에 포함시킨다.
# 사원의 이름, 급여, 부서 번호를 출력하시오. 단 사원의 급여가
# 그 사원이 속한 부서의 평균 급여보다 큰 경우만 출력하시오.
SELECT o.ename, o.sal, o.deptno
FROM emp o
WHERE o.sal > (SELECT AVG(i.sal)
               FROM emp i
               WHERE i.deptno = o.deptno);

# 각 부서별로 최고 급여를 받는 사원을 출력하라.
# 1
select deptno, empno, ename, sal
from emp
where (deptno, sal) in (select deptno, max(sal)
                        from emp
                        group by deptno);

# 2
select a.deptno, a.empno, a.ename, a.sal
from emp a,
     (select b.deptno, max(b.sal) msal
      from emp b
      group by deptno) c
where a.deptno = c.deptno
  and a.sal = c.msal;

# 3
SELECT deptno, empno, ename, sal
FROM emp e
WHERE e.sal = (SELECT max(sal)
               FROM emp WHERE deptno = e.deptno);

Set Operator

  • 두 질의의 결과를 가지고 집합 연산
  • UNION , UNION ALL , INTERSECT , MINUS
  • 우선 임의로 테이블 생성 a : {1, 2, 3} / b : {2, 3, 4}
  • create table a ( name int ); create table b ( name int ); insert into a value ('1'); insert into a value ('2'); insert into a value ('3'); insert into b value ('2'); insert into b value ('3'); insert into b value ('4');
# UNION : 합집합 (중복 제거)
select * from a union select * from b;
# UNION ALL : 합집합 (중복 포함)
select * from a union all select * from b;
# INTERSECT : 교집합
# - MySQL에서는 지원하지 않는다.
select * from a intersect select * from b; # 불가
select a.name from a, b where a.name = b.name;
# minus : 차집합
# - MySql 에서 지원하지 않는다.
select * from a minus select * from b;
select a.name from a where a.name not in (select b.name from b);

RANK() 함수

  • 요소에 대해 순서를 매기는 함수
  • MySQL 8 이상에서 사용가능
SELECT sal, ename,
			rank() over(order by sal desc) AS ranking
FROM emp;

 

728x90
728x90

Final

1-1. final 클래스

  • 자바에서 final 클래스는 다른 클래스가 그것을 상속받을 수 없게 하는 특별한 종류의 클래스이다.
  • final 키워드를 클래스 선언에 추가함으로써, 해당 클래스는 ‘최종적’이며 변경할 수 없다는 것을 의미한다.

final 클래스의 필요성

  1. 불변성 보장
    • 클래스가 일단 생성되면 그 상태가 변경되지 않도록 함으로써, 안정성과 보안을 향상시킨다.
  2. 상속 방지
    • 특정 클래스의 설계와 구현이 그대로 유지되어야 할 때 중요하다.
  3. 불변 클래스 생성
    • final 클래스는 불변 객체를 만드는 데 유용한다.
    • 불변 객체는 생성 후 그 상태가 변경되지 않으므로, 여러 면에서 프로그램의 신뢰성을 높일 수 있다.
  4. 성능 최적화
    • 컴파일러와 JVM은 final 클래스에 대해 성능 최적화를 수행할 수 있다.
    • final 클래스의 메소드는 오버라이딩되지 않기 때문에, 컴파일 타임에 메소드 호출이 결정될 수 있어, 실행 시간이 단축될 수 있다ㅏ.

final 클래스의 특성

  • 확장 불가능
    • 다른 클래스는 final 클래스를 상속받을 수 없다.
    • → 이는 final 클래스의 모든 메소드가 상속되거나 오버라이딩될 수 없음을 의미한다.
  • 메소드 오버라이딩 방지
    • final 클래스 내의 모든 메소드는 자동으로 final 로 간주된다.

💡 final 클래스는 코드의 안정성과 유지 보수성을 높이는 데 기여할 수 있으며, 특정한 사용 사례에서 중요한 역할을 한다. 클래스의 설계 의도를 명확히 하고, 불필요한 상속과 변경을 방지하여 프로그램의 견고성을 높이고자 할 때 final 클래스를 사용하는 것이 좋다.


1-2. final 클래스 예제

final class SecurityConfig {
    private static final String ENCRYPTION_KEY = "ComplexKey123!";

    private SecurityConfig() {
				// 생성자를 private으로 선언하여 외부에서 인스턴스화 방지
    }

    public static String getEncryptionKey() {
        return ENCRYPTION_KEY;
    }
}

public class FinalEx {
    public static void main(String[] args) {
        String encryptionKey = SecurityConfig.getEncryptionKey();
        System.out.println("암호화 키: " + encryptionKey);
    }
}
  • SecurityConfig 클래스 : final 로 선언되어 있어 상속 불가능
  • Private 생성자 : 클래스 외부에서 인스턴스를 생성할 수 없다.
  • 클래스가 유틸리티 목적으로만 사용되도록 의도된 것
  • Main 클래스 : SecurityConfig 클래스의 정적 메소드를 호출하여 암호화 키를 가져옴
  • 이 예제는 final 클래스를 사용하여 클래스의 불변성을 보장하고, 보안 관련 중요한 설정이 외부에서 변경되는 것을 방지하는 방법을 보여준다.

1-3. Java JDK의 final 클래스

  • JDK 내에서 final 클래스의 사용은 주로 안정성과 불변성을 확보하기 위해 이루어진다.
  • (변경되어서는 안되는 중요한 클래스들이 포함)
  • java.lang.String , java.lang.Math , java.lang.System , java.util.Collections 등
  • → 정적 메소드만 사용가능

2-1. final 필드

  • 자바에서 final 필드는 한 번 초기화되면 그 값을 변경할 수 없는 필드를 의미한다.
  • 상수를 정의하거나, 객체의 불변성을 보장하는 데 사용

final 필드의 필요성

  1. 상수 정의
    • 수학적 상수, 설정 값 등 프로그램 전반에 걸쳐 일관되게 사용되어야 하는 값들을 final 필드로 정의
  2. 불변 객체 생성
    • 객체의 불변성을 보장하려면, 객체가 생성된 후에는 그 상태가 변경되지 않도록 해야함
    • → 객체의 예측 가능성과 신뢰성을 높인다.
  3. 스레드 안정성
    • 멀티스레딩 환경에서 final 필드는 스레드 간의 안전한 읽기 작업을 보장한다.
    • 한 번 초기화된 final 필드의 값은 변경되지 않으므로, 스레드 간에 동기화 없이 안전하게 읽을 수 있다.
  4. 메모리 가시성 보장
    • 객체가 생성될 때 한 번만 쓰여지고, 이후에는 변경되지 않기 때문에, JVM은 메모리 가시성을 보장한다.
    • 즉, final 필드의 값은 모든 스레드에게 일관되게 보여진다.

final 필드의 특성

  • 초기화 제한
    • final 필드는 선언 시 또는 생성자에서만 초기화할 수 있다.
  • 객체의 핵심 속성 보호
    • 객체가 특정한 상태를 유지해야 할 때, 예를 들어 설정 값이나 중요한 데이터를 final 필드로 선언함으로써, 해당 값의 무결성을 유지할 수 있다.

💡 final 필드는 프로그램의 안정성과 무결성을 높이는 중요한 방법이다. 이러한 필드는 프로그램이 더욱 견고하고 안정적으로 동작하도록 돕고, 예측 가능한 동작을 보장하는 데 기여한다.


2-2. final 필드 예제

class Person {
    private final int id;
    private String name;

    public Person(int id, String name) {
        this.id = id;
        this.name = name;
    }

    public int getId() {
        return id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

public class FinalFieldEx {
    public static void main(String[] args) {
        Person person = new Person(1001, "John Doe");
        System.out.println("사람의 ID: " + person.getId());
        System.out.println("사람의 이름: " + person.getName());

        person.setName("Jane Doe");
        System.out.println("변경된 이름: " + person.getName());
    }
}
  • Person 클래스, 생성자
    • Person 객체가 생성될 때, 식별 번호와 이름은 생성자를 통해 초기화된다. 식별 번호는 final 필드이므로, 이후에는 변경 불가

3-1. final 메소드

  • 한 번 선언되면 하위 클래스에서 오버라이딩(재정의)할 수 없다.
  • → 클래스의 핵심적인 기능을 안정적으로 유지하기 위해 사용된다.

final 메소드의 필요성

  1. 메소드의 무결성 보장
    • final 메소드는 변경되거나 재정의될 수 없다.
  2. 오버라이딩 방지
  3. 보안 강화
  4. 예측 가능한 동작
    • 개발자는 final 메소드가 항상 동일한 방식으로 동작한다는 것을 알고 있으므로, 의도치 않은 오류나 버그를 줄일 수 있다.

final 메소드의 특성

  • 재정의 불가능
  • 클래스의 동작 보호

💡 final 메소드는 객체 지향 프로그래밍에서 클래스의 기능을 보호하고, 안정적인 동작을 보장하는 중요한 도구이다. 이는 프로그램의 견고성을 높이고, 예상치 못한 동작으로부터 시스템을 보호하는 데 중요한 역할을 한다.


3-2. final 메소드 예제

class BankAccount {
    private final int accountNumber;
    private double balance;

    public BankAccount(int accountNumber, double initialBalance) {
        this.accountNumber = accountNumber;
        this.balance = initialBalance;
    }

    public final String getAccountInfo() {
        return "계좌 번호: " + accountNumber + ", 잔액: " + balance;
    }

    public void deposit(double amount) {
        balance += amount;
    }

    public void withdraw(double amount) {
        balance -= amount;
    }
}

public class FinalMethodEx {
    public static void main(String[] args) {
        BankAccount account = new BankAccount(12345, 1000.0);
        System.out.println(account.getAccountInfo());   // 계좌 번호: 12345, 잔액: 1000.0
        account.deposit(500);
        System.out.println(account.getAccountInfo());   // 계좌 번호: 12345, 잔액: 1500.0
        account.withdraw(200);
        System.out.println(account.getAccountInfo());   // 계좌 번호: 12345, 잔액: 1300.0
    }
}
  • final 메소드는 클래스의 동작을 안정적으로 유지하고, 프로그램의 신뢰성을 향상시키는 데 기여한다.
728x90

'Spring > TIL - 멋쟁이사자처럼' 카테고리의 다른 글

TIL - 3월 27일 : HTML  (1) 2024.03.29
728x90

String 클래스

== 와 equals()

  • == : 비교하는 두 대상의 주소값을 비교
  • equals() : 비교하는 두 대상의 값을 비교
public class StringExam {
    public static void main(String[] args) {
        String str1 = "hello";
        String str2 = "hello";
        String str3 = new String("hello");
        String str4 = new String("hello");

        System.out.println(str1 == str2);      // true
        System.out.println(str1.equals(str2)); // true

        System.out.println(str2 == str3);      // false
        System.out.println(str2.equals(str3)); // true

        System.out.println(str3 == str4);      // false
        System.out.println(str3.equals(str4)); // true
    }
}

추상 클래스

  • abstract 키워드를 사용하여 클래스를 정의한다.
  • 확장 만을 위한 용도로 정의되는 클래스
  • 추상 클래스는 인스턴스가 될 수 없다.
  • 추상 클래스를 상속받는 자손이 인스턴스가 된다.
  • 추상 클래스는 보통 1개 이상의 추상 메소드를 가진다. (없어도 오류 발생은 X)
public abstract class 클래스명 { ... }

추상 메소드

  • 추상 메소드는 메소드에 대한 구현을 가지지 않는다.
  • 추상 클래스의 자식 클래스가 해당 메소드를 구현 하도록 강요하기 위해 존재
  • 추상 메소드는 추상 클래스에만 조재할 수 있다.

✔ 추상 클래스를 사용하는 이유

  1. 공통된 필드와 메서드를 통일할 목적
    • 필드와 메서드 이름을 통일하여 유지보수성을 높이고 통일성을 유지할 수 있다.
  2. 실체 클래스 구현시, 시간절약
    • 강제로 주어지는 필드와 메서드를 가지고 실체 클래스의 성격대로 구현만 하면 된다.
    • 설계 시간이 절약되며, 구현하는데만 집중할 수 있다.
  3. 규격에 맞는 실체 클래스 구현
    • 공통된 속성은 규격에 맞게 구현할 수 있다는 의미
    • → 추상 클래스를 상속받은 실체 클래스들은 반드시 추상 메서드를 재정의해서 실행 내용을 작성해야 하기 때문
    • 그 외의 것은 자유롭게 구현이 가능하다.

중요한 것은, 소스 수정시 다른 소스의 영향도를 적게 가져가면서 변화에는 유연하게 만들기 위해 추상클래스를 사용한다는 점 !

추상클래스의 상속

  • 추상 클래스의 상속에도 extends 키워드 사용
  • 추상 클래스를 상속하는 클래스는 반드시 추상 클래스의 추상 메소드를 구현해야 함
  • 추상 클래스간의 상속에서는 추상클래스를 구현하지 않아도 됨
  • 추상 클래스의 추상 메소드를 상속받아 정의하는 예시
abstract class Shape {
    public abstract double calculateArea();
}

class Triangle extends Shape {
    private double x;
    private double y;

    public Triangle(int x, int y) {
        this.x = x;
        this.y = y;
    }

    public double calculateArea() {
        return this.x * this.y / 2;
    }
}

class Rectangle extends Shape {
    private double x;
    private double y;

    public Rectangle(int x, int y) {
        this.x = x;
        this.y = y;
    }

    public double calculateArea() {
        return this.x * this.y;
    }
}

public class ShapeDemo {
    public static void main(String[] args) {
        Shape triangle = new Triangle(10, 5);
        System.out.println("삼각형의 너비: " + triangle.calculateArea());

        Shape rectangle = new Rectangle(10, 20);
        System.out.println("사각형의 너비: " + rectangle.calculateArea());
    }
}
  • 추상 클래스의 연속 상속
abstract class Aclass {
	public abstract void Amethod();  // 추상 메소드
}
abstract class Bclass extends Aclass { // 추상 클래스를 상속받은 추상 클래스
	public abstract void Bmethod();
}

public class Cclass extends Bclass {
	public void Amethod() { ... } // 반드시 구현해야 함
	public void Amethod() { ... } // 반드시 구현해야 함
**}**

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

  • 디자인 패턴 중 하나로, 알고리즘의 구조를 메소드에 정의하고,
  • 알고리즘의 일부 단계를 서브클래스에서 구현하도록 하여 알고리즘의 일부 변경을 허용하는 패턴이다.
  • → 공통의 알고리즘 과정이 있지만, 그 과정 중 일부가 클래스마다 다를 때 유용하다.
  • 추상 클래스를 사용하여 템플릿 메소드를 정의하고, 구체적인 작업은 서브클래스에서 오버라이드하여 구현

구조

  • 추상 클래스(Abstract Class)
    • 알고리즘의 단계를 정의하는 템플릿 메소드와 알고리즘의 일부를 구현하는 하나 이상의 추상 메소드로 구성
  • 구체 클래스(Concrete Class)
    • 추상 클래스를 상속받아 추상 메소드를 구현한다. (알고리즘의 일부 단계를 구체화)
abstract class BeverageRecipe {
    public **final** void prepareRecipe() {  // 템플릿 메소드
        boilWater();
        brew();
        pourInCup();
        addCondiments();
    }

    abstract void brew(); // 추상 메소드

    abstract void addCondiments(); // 추상 메소드

    public void boilWater() {
        System.out.println("물을 끓입니다.");
    }

    public void pourInCup() {
        System.out.println("컵에 따릅니다.");
    }
}

class Coffee extends BeverageRecipe {
    @Override
    void brew() {
        System.out.println("필터를 통해 커피를 우려냅니다.");
    }

    @Override
    void addCondiments() {
        System.out.println("설탕과 우유를 추가합니다.");
    }
}

class Tea extends BeverageRecipe {
    @Override
    void brew() {
        System.out.println("차를 우려냅니다.");
    }

    @Override
    void addCondiments() {
        System.out.println("레몬을 추가합니다.");
    }
}

public class TemplateMethodPatternDemo {
    public static void main(String[] args) {
        BeverageRecipe tea = new Tea();
        tea.prepareRecipe();

        BeverageRecipe coffee = new Coffee();
        coffee.prepareRecipe();
    }
}

Java Interface

개념

  • 서로 관계가 없는 물체들이 상호 작용을 하기 위해서 사용하는 장치나 시스템
  • 클래스 구조상의 관계와 상관 없이 클래스들에 의해 구현되어질 수 있는 규약

목적

  • 클래스들 사이의 유사한 특성을 부자연스러운 상속 관계를 설정하지 않고 얻어냄

활용

  • 하나 또는 그 이상의 클래스들에서 똑같이 구현되어질 법한 메소드를 선언하는 경우
  • 클래스 자체를 드러내지 않고 객체의 프로그래밍 인터페이스를 제공하는 경우

클래스 vs 인터페이스

  • 완결한 메소드(Concrete method)
    • 메소드의 구현을 포함한 일반적인 메소드를 concrete method라 함
    • 추상 메소드(Abstract Method)의 반대 개념

✔ 인터페이스의 상속

  • 인터페이스는 다중 상속을 지원하지 않는 자바에서 다중 상속의 장점을 활용하기 위해 도입
  • 한 클래스는 하나의 부모 클래스를 가지며 하나 이상의 인터페이스를 구현할 수 있다.
  • 인터페이스 사이에서는 다중 상속이 가능하다.
  • interface 키워드로 선언하고 implements 키워드로 사용
  • 인터페이스를 구현한 클래스에서 추상 메소드를 반드시 정의해야 함
interface Ainter {
    public void aMethod();
    public void same();
}
interface Binter extends Ainter{
    public void bMethod();
}
interface Cinter{
    public void cMethod();
    public void same();
}
interface Dinter extends Cinter, Binter{
    // 인터페이스들 간에는 다중 상속이 가능하다.
    public void dMethod();
}
class DImpl implements Dinter{
    @Override
    public void aMethod() {
        System.out.println("aMethod 구현");
    }
    @Override
    public void bMethod() {

    }
    @Override
    public void same() {

    }
    @Override
    public void cMethod() {
        System.out.println("aMethod 구현");
    }
    @Override
    public void dMethod() {
        System.out.println("aMethod 구현");
    }
}

public class InterfaceDemo{
    public static void main(String[] args) {
        // 인터페이스도 타입이다.
        Ainter ainter = new DImpl();
        Cinter cInter = new DImpl();

        // 자기가 정의한 것만 사용 가능
        ainter.aMethod();
        cInter.cMethod();

        Binter binter = new DImpl();
        Dinter dinter = new DImpl();

        binter.aMethod();
        binter.bMethod();
        binter.same();

        /* 타입이 아는 것 까지만 쓸 수 있고,
         * 외의 것을 쓰고 싶다면 형변환이 필요 */
        ((DImpl)ainter).say();
    }
}

default 메소드

  • 인터페이스가 default 키워드로 선언되면 메소드가 구현될 수 있다.
  • 또한 이를 구현하는 클래스는 default 메소드를 오버라이딩 할 수 있다.
  • 인터페이스가 변경이 되면, 인터페이스를 구현하는 모든 클래스들이 해당 메소드를 구현해야 하는 문제가 있다.
  • → 이런 문제를 해결하기 위하여 인터페이스에 메소드를 구현해 놓을 수 있도록 함
interface Calculator {
    public int plus(int i, int j);

    public int multiple(int i, int j);

    default int exec(int i, int j) {  // default로 선언함으로 메소드를 구현할 수 있다.
        return i + j;
    }
}

class MyCalculator implements Calculator {
    @Override
    public int plus(int i, int j) {
        return i + j;
    }

    @Override
    public int multiple(int i, int j) {
        return i * j;
    }
}

public class CalculatorDemo {
    public static void main(String[] args) {
        Calculator cal = new MyCalculator();

        System.out.println(cal.plus(5, 10));
        System.out.println(cal.multiple(5, 10));
        
        int value = cal.exec(5, 10);
        System.out.println(value);
    }
}

인터페이스의 static

변수

  • 인터페이스에서 int a = 10; 과 같이 멤버 변수를 선언하게 되면 static final 로서 선언된다. (생략 가능, 생략 하더라도 static final 로서 선언됨)
  • 즉, 인터페이스에서 변수를 선언하게 되면, 그 변수는 상수가 된다.
  • → 상수로서 변수와 구분을 위해 대문자로 선언하는 것이 관례이다.

static 메소드

  • 인터페이스에 static 메소드를 정의하는 것은, 클래스에 static 을 정의하는 것과 동일하다.
  • 인터페이스에서 메소드 구현이 가능하다.
  • 반드시 클래스 명으로 메소드를 호출해야 한다.
728x90
728x90

HTML

인터넷과 웹의 시작

미국 국방성에서 시작. 1969년 현재 인터넷의 모태가 되는 ARPANET이 개발되었다. 1989년 팀 버너스 리는 월드 와이드 웹(World Wide Wep, WWW)을 개발하였다. 문서와 문서를 연결하는 하이퍼링크(Hyper Link) 개념이 도입되었고, 1991년에 배포되었으며 1993년에 소스코드가 공개되었다.

 

웹 브라우저의 역사

  • 1993년 : 최초의 GUI 환경의 '모자이크' 탄생
  • 1996년 ~ 2008년 말 : 1차 브라우저 전쟁. 모자이크를 개발했던 마크 엔더리슨은 '넷스케이프'를, 마이크로소프트는 '인터넷 익스플로러'를 개발. 운영체제에 기본으로 탑제되어 제공되던 익스플로러가 넷스케이프를 이기고 대부분의 점유율을 확보
  • 2008년 12월 : 구글 크롬 정식 출시
  • 2010년 : 인터넷 익스플로러가 최신 표준을 지원하지 않는 문제가 발생
  • 2009년 ~ 2015년 : 2차 브라우저 전쟁. 2022년 2월 기준 데스크탑 64.89%의 점유율로 크롬이 승리

HTML5

최신 웹 기술로, 단순히 웹 문서를 작성할 때 사용되는 마크업 랭귀지(HTML)의 문법적(syntactic) 버전 뿐만 아니라 새로운 DOM API 스펙을 포함한다. 일렉트론(Electron)등의 기술을 사용하면 애플리케이션 웹 기반으로 개발이 가능하다.

 

시작 태그, 끝 태그, 내용

<h1>Hello</h1>
  • 시작 태그 : <h1>
  • 끝 태그: </h1>
  • 내용: Hello
  • 요소(element): 시작 태그 + 내용 + 끝 태그
  • 내용엔 다른 요소들이 올 수도 있다.

속성

<a href="http://www.naver.com">naver</a>

 

 

기본 구조

<!DOCTYPE html>
<html>
    <head>
        <title>문서의 제목</title>
    </head>
    <body>
        문서의 내용
    </body>
</html>

 

head

웹 브라우저에 문서 정보를 알려주는 태그. 화면에 보이는 부분은 아니다. <mata>, <title> 등이 쓰이고 스타일시트 파일도 이곳에서 연결해준다.

 

meta 태그

  1. 문자셋 정의: 문서의 문자 인코딩을 지정
<mate charset="UTF-8">

2. 뷰포트 설정: 반응형 웹 디자인에 필수적인 속성. 모바일 브라우저에서 페이지가 어떻게 보여질지 제어한다.

<meta name="viewport" content="width=device-width, initial-scale=1.0">

3. 키워드: 페이지 내용과 관련된 키워드를 제공하고 검색엔진 최적화(SEO)에 도움이 된다.

<meta name="keywords" content="HTML, CSS, JavaScript">

4. 웹 페이지 설명: 웹 페이지의 간단한 설명을 제공. 검색엔진의 검색결과에서 페이지 아래에 표시되는 설명문

<meta name="description" content="Html 구조에 대해 설명합니다.">

이외에도 저자 설명, 리프레시 설정, 캐시 제어, 오픈 그래프 메타태그 등의 설정을 할 수 있게 해주는 태그이다.


html 태그 종류

제목

h1, h2, h3, h4, h5, h6

h1은 가장 큰 제목, h6는 가장 작은 제목

 

줄바꿈

<br />

 

가로줄

<hr />

 

앵커

하이퍼링크 태그를 의미한다. 내용 부분을 클릭하면 해당 주소로 이동

<a href="주소">내용</a>

 

글자의 모양

<b>, <i>, <small>, <sub>, <sup>, <ins>, <del>

글자의 모양은 태그를 이용하지 않고 보통 CSS를 이용하는 것이 좋다

 

목록 태그/기본 목록

<ul> 순서가 없는 목록을 표현

<ol> 순서가 있는 목록을 표현

<li> 목록의 요소

 

목록 태그/정의 목록

<dl> 정의 목록 태그

<dt> 정의 용어 태그

<dd> 정의 설명 태그

 

테이블 태그

<table> 표

<tr> 표 내부의 행

<th> 제목 셀 태그

<td> 일반 셀 태그

 

- 테이블 속성

border 표의 테두리 두께

rowspan 세로로 셀 합치기

colspan 가로로 셀 합치기

 

이미지 태그

<img> 이미지

 

- 이미지 속성

src 이미지 경로

alt 이미지 설명

width 이미지 너비

height 이미지 높이

 

멀티미디어 태그

<audio> 오디오 파일

<video> 비디오 파일

 

입력양식 태그

form 입력 폼

input 입력 창

textarea 입력 영역

select 선택 폼

 

공간 분할 태그

<div> block 형식으로 공간 분할

<span> inline 형식으로 공간 분할

 

시멘틱 구조 태그

<header> 헤더

<nav> 네비게이션

<aside> 사이드에 위치하는 공간

<section> 여러 중심 내용을 감싸는 공간

<article> 내용

<footer> 푸터

<address> 주소

 

실습문제1 - 자기소개 페이지 만들기

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>자기소개 페이지</title>
</head>
<body>
    <header>
        <h1>지유빈의 자기소개 페이지</h1>
    </header>
    <hr/>
    <main>
        <img src="intro.png" alt="자기소개사진">
        <section>
            <h2>기본 자기소개</h2>
            <p>안녕하세요. 저는 멋쟁이사자처럼 백엔드스쿨 10기생 박경서입니다.</p>
            <p>저는 백엔드에 대해 공부하고 혼자서도 웹 페이지를 만들어보고싶습니다.</p>
        </section>
        <hr/>
        <section>
            <h2>취미 및 관심사</h2>
            <p>저의 취미는 야구 직관입니다.</p>
            <p>요즘 관심은 모루인형 만들기입니다.</p>
        </section>
        <hr/>
        <blockquote>늦었다고 생각할 때가 진짜 늦었다</blockquote>
        <cite>박명수</cite>
    </main>
    <hr/>
    <footer>
        <p>연락처 및 주소</p>
        <address>
            <p>주소 - 경기도 수원시</p>
            <p>연락처 - 010-1111-2222</p>
        </address>
    </footer>
</body>
</html>

실습문제2 - 블로그 포스트 페이지 만들기

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>블로그 페이지</title>
</head>
<body>
    <header>
        <h1>HTML의 기본</h1>
        <p><small>2024-03-27 박경서</small></p>
    </header>
    <hr/>
    <main>
        <img src="html.png" alt="html아이콘">
        <p>오늘은 <strong>html의 기본</strong>을 배워보았다.</p>
        <p><em>다양한 태그</em>를 이용해 실습도 해보았다.</p>
        <a href="https://www.tcpschool.com/html-tag-attrs/img-alt" target="_blank">실습의 기본</a>
    </main>
    <hr/>
    <section>
        <h4>댓글</h4>
        <ul>
            <li>재밌었겠내요</li>
            <li>저도 배워보고 싶어요</li>
            <li>다음엔 어떤 걸 배우나요?</li>
        </ul>
    </section>
</body>
</html>

실습문제3 - 제품 소개 페이지

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>제품 소개 페이지</title>
</head>
<body>
    <header>
        <h1>갤럭시 제품 소개</h1>
        <p>갤럭시는 한국 최고 기업 삼성에서 만들어진 최고의 스마트폰입니다.</p>
    </header>
    <hr/>
    <main>
        <img src="g1.jpg" alt="갤럭시사진1" width="400px">
        <img src="g2.jpg" alt="갤럭시사진1" width="400px">
        <ul>
            <li>예쁜 색감</li>
            <li>좋은 기능</li>
        </ul>
    </main>
    <hr/>
    <hr/>
    <section>
        <article>
            <h3>사용자1</h3>
            <p>너무 잘 쓰고있어요.</p>
        </article>
        <hr/>
        <article>
            <h3>사용자2</h3>
            <p>약간 버벅거려요.</p>
        </article>
        <hr/>
    </section>
    <footer>
        <p>제품 구매 페이지</p>
        <a href="https://search.naver.com/search.naver?ssc=tab.nx.all&where=nexearch&sm=tab_jum&query=%EA%B0%A4%EB%9F%AD%EC%8B%9C" target="_blank">구매 관련 홈페이지</a>
    </footer>
</body>
</html>
728x90

'Spring > TIL - 멋쟁이사자처럼' 카테고리의 다른 글

4월 11일 TIL : final  (0) 2024.05.03
728x90

추상화

  • 중요한 것은 남기고, 불필요한 것은 제거하는 것

캡슐화(encapsulation)

  • 관련된 것을 잘 모아서 가지고 있는 것
    → 응집도(Cohesion)가 높다고 표현함

 

* 좋은 객체는 응집도는 높고 결합도(Coupling)는 낮다.

  • 응집도 : 응집도는 모듈의 독립성을 나타내는 개념으로, 모듈 내부 구성요소 간 연관 정도
  • 결합도 : 소프트웨어 구조에서 모듈 간의 관련성을 측정하는 척도

객체의 역할, 책임 그리고 협력

  • 좋은 객체란 역할과 책임에 충실하면서 다른 객체와 잘 협력하여 동작하는 객체
  • 나쁜 객체란 여러가지 역할을 한 가지 객체에 부여하거나, 이름과 맞지 않는 속성과 기능을 가지도록 하거나 제대로 동작하지 않는 객체
    • 다른 객체와도 동작이 매끄럽지 않는 객체

다형성

  • 프로그램 언어의 각 요소들(상수, 변수, 식, 오브젝트, 함수, 메소드 등)이 다양한 자료형(type)에 속하는 것이 허가되는 성질

메소드 오버로딩(Overloading)

  • 메서드의 이름은 같고 매개변수의 갯수나 타입이 다른 함수를 정의하는 것을 의미한다.
  • 리턴값만 다르게 갖는 오버로딩은 작성할 수 없다.

패키지

  • 클래스는 패키지를 이용하여 관련된 클래스를 관리한다.
  • 폴더와 거의 같은 기능을 제공한다고 생각하면 된다.
  • 이름 규칙
    • 보통 도메인 이름을 거꾸로 적은 후에 프로젝트 이름 등을 붙여서 만든다.

패키지 선언 방법

  • package 패키지명 : 주석문이나 빈줄을 제외하고 가장 윗 줄에 선언한다.
  • 사용할 때는 import 패키지명.클래스명;
  • cmd를 이용해서 컴파일시
    • javac -d 경로명 *.java
    • -d 옵션을 사용
  • 실행시
    • java 패키지명.클래스명

상속

  • ‘OO는 OO다. OO는 OO의 종류 중 하나다.’ 라고 표현할 수 있다면 상속관계이다.
  • is-a 관계 혹은 kind of 관계라고 말하기도 한다.
  • 상속 = 일반화 + 확장

상속 선언 방법

[접근제한자] [abstract | final] class 클래스명 extends 부모클래스명 {
	...
}
  • 아무것도 상속받지 않으면 자동으로 java.lang.Object 를 상속받음
  • 최상위 부모 클래스는 아무것도 상속받지 않으므로 결국 모든 클래스는 Object 를 상속받으므로 Object 의 자손이다.

다형성 - 메소드 오버라이딩(Overriding)

  • 상위 클래스의 메서드를 하위 클래스가 재정의 하는 것
  • 메서드의 이름은 물론 파라미터의 갯수나 타입도 동일해야 하며, 주로 상위 클래스의 동작을 상속받은 하위 클래스에서 변경하기 위해 사용
  • 부모 타입으로 자손 타입을 참조할 수 있다.
  • 이때, 메소드가 오버라이딩된 경우 무조건 자식의 메소드가 실행된다.
  • 메소드와 별개로, 필드는 Type을 따라감
// 두 클래스 모두 run() 메소드를 가지고 있을 경우
Car car = new Bus();
car.run();
// Bus의 run 메소드가 실행됨

중요한 필드는 은닉하고, 필드는 메소드를 통해서만 접근해서 사용해야 한다.

 

Object가 오버라이딩하도록 제공하는 메소드

  • toString() / equals() / hashCode()
  • Intellij의 원하는 클래스에서 <마우스 우클릭> 후 생성하면 기본 형식으로 오버라이딩된다.
  • 형식은 원하는대로 바꿔도 된다.
  • Object 메소드 오버라이딩 예시

생성자

  • 인스턴스를 생성할 때 사용한다.
  • 어떤 값을 가진채로 인스턴스가 만들어지게 하고 싶을 때 사용
  • 클래스 작성시 생성자를 따로 만들지 않았다면 자동으로 기본 생성자가 생성됨
    • 기본생성자 : 매개변수를 하나도 받지 않는 생성자

생성자 오버로딩

  • 생성자는 매개변수의 개수가 다르거나, 타입이 다르다면 여러개를 가질 수 있다.
  • ex)
public class Car {
    String name;
    int speed;
    
		// 기본생성자
    public Car() {
        System.out.println("car() 생성자 호출");
    }
    
    // 매개변수가 있는 생성자 (오버로딩)
    public Car(String name) {
        this.name = name;
    }

    public Car(int speed, String name) {
        this.name = name;
        this.speed = speed;
    }
}

this()

  • this() 생성자
    • 자기 자신의 생성자를 말한다.
    • 생성자 안에서만 사용가능하다.
    • 인스턴스 자기 자신을 참조할 때 사용하는 키워드이다.
    • 생성자 안에서 super() 생성자를 호출하는 코드 다음 or 첫번째 줄에 위치해야 한다.
      •  

super()

  • super() 생성자
    • 부모 생성자를 의미한다.
    • 부모의 생성자를 호출할 때 사용한다.
    • 생성자 안에서만 사용가능하다.
    • 생성자 안에서 첫번째 줄에만 올 수 있다.
    • 사용자가 생성자를 호출하는 코드를 작성하지 않았다면 자동으로 부모의 기본 생성자가 호출된다.
    • 부모 클래스가 기본 생성자를 가지고 있지 않다면, 사용자는 반드시 직접 super() 생성자를 호출하는 코드를 작성
728x90
728x90

3월 25일 월요일 학습 내용


객체지향

  • 객체들의 모임으로 파악하고자 하는 것
  • 각각의 객체는 메시지를 주고받고, 데이터를 처리할 수 있음
  • 객체지향 관점에서의 서점
    • 책을 관리하는 것은? <책장>
    • 손님을 관리하는 것은? <방명록>
    • 돈을 관리하는 것은? <금고>


객체 지향 프로그래밍

  • 객체 지향 프로그래밍은 컴퓨터 프로그래밍의 패러다임 중 하나이다.  
  • “객체”들의 모임으로 파악하고자 하는 것
    → 각각의 객체는 메시지를 주고받고, 데이터를 처리할 수 있다.
  • 클래스 class
  • 오브젝트 object
  • 인스턴스 instance
  • 참조형 변수 reference variable
  • 핵심 : 메시징 => 객체가 어떻게 해야 하는가가 아니라 무엇을 해야하는가를 설명한다는 것 (메소드)


final 키워드

  • 변수(variable), 메서드(method), 또는 클래스(class)에 사용 가능
  • 변수에 final을 붙이면 이 변수는 수정할 수 없다는 의미
  • 메서드에 final을 붙이면 override를 제한
  • final 키워드를 클래스에 붙이면 상속 불가능 클래스


접근제한자

  • public, protected, package, private가 있다.
    • public : 외부 클래스가 자유롭게 사용할 수 있도록 한다.
    • protected : 같은 패키지 또는 자식 클래스에서 사용할 수 있도록 한다.
    • default**(**package) : 같은 패키지에서 사용할 수 있도록 한다.
    • private : 외부 클래스에서 사용할 수 없도록 한다.접근제한자

  • package안의 하위 package가 있더라고 다른 package로 보기 때문에 사용하고자하는 package를 import 해줘야한다.

 

<예시 코드>

  • com.example.util 패키지 안에 있는 Calculator 클래스
package com.example.util;

public class Calculator {
    public int plus(int a, int b){
        return a+b;
    }
    public int minus(int a, int b){
        return a-b;
    }
}
  • com.example.main 패키지 안에 있는 CalculatorTest 클래스
package com.example.main;

// util 패키지에 있는 클래스를 사용하기 위해 import
import com.example.util.Calculator; 

public class CalculatorTest {
    public static void main(String[] args) {
        Calculator cal = new Calculator();
        System.out.println(cal.plus(1,5));
        System.out.println(cal.minus(5,2));
    }
}

클래스

    • 자바에서 클래스는 설계도라고 본다.
    • 클래스는 필드(속성, Field)와 메소드(행위, 기능, Method)를 가진다.
    • 클래스에는 객체를 생성하기 위한 필드와 메소드가 정의되어 있어야한다.
    • 클래스로부터 객체를 만드는 과정을 인스턴스화라고 한다.
    • 하나의 클래스로부터 여러 객체를 만들 수 있음
    • 클래스로부터 만들어진 객체를 해당 클래스의 인스턴스라고 함
    • main 메소드가 없는 클래스는 실행되지 않음

 

필드(field)

  • 클래스가 가지는 속성
  • 다른 언어의 경우 멤버변수라고 하는 경우도 있다.
  • static 키워드가 함께 사용되는 필드를 클래스 필드, 함께 사용되지 않는 필드를 인스턴스 필드라고 한다.

필드 선언 방법

[접근제한자] [static] [final] 타입 필드명 [=초기값];

String name;
String address = "경기도 수원시";
public int age = 50;
protected boolean flag;​

 

  • 대괄호 안에 있는 내용은 생략가능하다는 뜻
  • 필드의 첫번째 글자는 소문자로 시작하는 것이 관례이며, 자바의 경우 흔히 카멜 케이스로 작성
  • 타입(type)은 기본형(boolean, byte, …)과 참조타입(class, 인터페이스, 배열) 등 사용가능
  • 초기값이 없는 경우
    • 참조형일 경우 null / boolean형일 경우 false / 나머지 기본형은 모두 0 으로 초기화된다.

 

클래스 선언

클래스 선언 방법

public class 클래스명 {

}
  • Dice 클래스와 클래스의 필드 및 메소드 선언
package com.example.util;

public class Dice {

    private int face;
    private int eye;

    public void roll(){
        eye = (int)(Math.random()*face) + 1;
    }
    public int getEye(){
        return eye;
    }
    public void setFace(int face) {
        this.face = face;
    }
}

 

객체 선언

객체 선언 방법

   클래스명 객체명 = new 클래스명();
// 참조타입 참조변수 new연산자 생성자
  • 메모리
    • new 연산자를 사용할 때마다 메모리에 인스턴스가 생성.
    • 인스턴스는 더 이상 참조되는 것이 없을 때, 보통 메모리 부족시 가비지 컬렉션(Garbage Collection)에 저장
    • static한 필드는 클래스가 로딩될 때 딱 한번 메모리에 올라가고 초기화
    • 인스턴스 메소드(static이 안붙은 메소드)는 인스턴스를 생성하고나서 레퍼런스 변 수를 이용해 사용
    • 클래스 메소드는 클래스명.메소드명() 으로 사용가능
    • 메소드 안에 선언된 변수들은 메소드가 실행될 때 메모리에 생성되었다가, 메소드가 종료될 때 사라짐
  • DiceTest 클래스에서 Dice 클래스 객체 생성
package com.example.main;

import com.example.util.Dice;

public class DiceTest {
    public static void main(String[] args) {
        Dice dice = new Dice();
        dice.setFace(6);
        dice.roll();
        int eye = dice.getEye();
        System.out.println(eye);
    }
}

 

메소드 선언

  • 객체지향의 핵심은 “메시징”이다.
  • 자율적인 객체는 스스로 정한 원칙에 따라 판단하고 스스로의 의지를 기반으로 행동하는 객체이다.
  • 객체가 어떤 행동을 하는 이유는 다른 객체로부터 요청을 수신했기 때문이다.

메소드 선언 방법

[접근제한자][static]리턴type 메소드이름([매개변수,...]) {
실행문..
}
    • 메소드 이름은 소문자로 시작하는 것이 관례이다.
    • 클래스의 메소드를 호출하려면
      • 클래스에 대한 인스턴스를 생성하거나
      • 래퍼런스 변수를 이용하여 메시지를 전송한다. (메소드 호출)
      • static 메소드는 인스턴스를 생성하지 않아도 호출할 수 있다.
  • 전달인자 : 메소드를 호출할 때 전달하는 실제 값
  • 매개변수 : 메소드 정의 부분에 나열되어있는 변수
728x90
728x90

Servlet(서블릿)


1. Servlet(서블릿)

 

서블릿을 한 줄로 정의하자면,

클라이언트의 요청을 처리하고, 그 결과를 반환하는 Servlet 클래스의 구현 규칙을 지킨 자바 웹 프로그래밍 기술


이라고 할 수 있겠다.

 

간단히 말해, 서블릿이란 자바를 사용하여 웹을 만들기 위해 필요한 기술이다. 그런데 좀더 들어가서 설명하면 

클라이언트가 어떠한 요청을 하면 그에 대한 결과를 다시 전송해주어야 하는데, 이러한 역할을 하는 자바 프로그램이다.

 

예를 들어, 어떠한 사용자가 로그인을 하려고 할 때. 사용자는 아이디와 비밀번호를 입력하고, 로그인 버튼을 누른다. 

그때 서버는 클라이언트의 아이디와 비밀번호를 확인하고, 다음 페이지를 띄워주어야 하는데, 이러한 역할을 수행하는 

것이 바로 서블릿(Servlet)이다. 그래서 서블릿은 자바로 구현 된 *CGI라고 흔히 말한다.

 

[ Servlet 특징 ]

  • 클라이언트의 요청에 대해 동적으로 작동하는 웹 어플리케이션 컴포넌트
  • html을 사용하여 요청에 응답한다.
  • Java Thread를 이용하여 동작한다.
  • MVC 패턴에서 Controller로 이용된다.
  • HTTP 프로토콜 서비스를 지원하는 javax.servlet.http.HttpServlet 클래스를 상속받는다.
  • UDP보다 처리 속도가 느리다.
  • HTML 변경 시 Servlet을 재컴파일해야 하는 단점이 있다.

일반적으로 웹서버는 정적인 페이지만을 제공한다. 그렇기 때문에 동적인 페이지를 제공하기 위해서 웹서버는 

다른 곳에 도움을 요청하여 동적인 페이지를 작성해야한다. 동적인 페이지로는 임의의 이미지만을 보여주는 페이지와 같이 사용자가 요청한 시점에 페이지를 생성해서 전달해 주는 것을 의미한다. 여기서 웹서버가 동적인 페이지를 제공할 수 있도록 도와주는 어플리케이션이 서블릿이며, 동적인 페이지를 생성하는 어플리케이션이 CGI이다. 

 

 

[ Servlet 동작 방식 ]

 

Servlet&nbsp;동작 방식

 

 

  1. 사용자(클라이언트)가 URL을 입력하면 HTTP Request가 Servlet Container로 전송한다.
  2. 요청을 전송받은 Servlet Container는 HttpServletRequest, HttpServletResponse 객체를 생성한다.
  3. web.xml을 기반으로 사용자가 요청한 URL이 어느 서블릿에 대한 요청인지 찾는다.
  4. 해당 서블릿에서 service메소드를 호출한 후 클리아언트의 GET, POST여부에 따라 doGet() 또는 doPost()를 호출한다.
  5. doGet() or doPost() 메소드는 동적 페이지를 생성한 후 HttpServletResponse객체에 응답을 보낸다.
  6. 응답이 끝나면 HttpServletRequest, HttpServletResponse 두 객체를 소멸시킨다.

 

 

Get과 Post에 대해서는 https://mangkyu.tistory.com/17 이 글을 참고하자.

 

 

 

Q) CGI(Common Gateway Interface)란?

 

CGI는 특별한 라이브러리나 도구를 의미하는 것이 아니고, 별도로 제작된 웹서버와 프로그램간의 교환방식이다. CGI방식은 어떠한 프로그래밍언어로도 구현이가능하며, 별도로 만들어 놓은 프로그램에 HTML의 Get or Post 방법으로 클라이언트의 데이터를 환경변수로 전달하고, 프로그램의 표준 출력 결과를 클라이언트에게 전송하는 것이다.

즉, 자바 어플리케이션 코딩을 하듯 웹 브라우저용 출력 화면을 만드는 방법이라고 할 수있다.

 

 

Q) HTTP 프로토콜을 이용한 서버와 클라이언트의 통신 과정은?

 

클라이언트는 정보를 얻기 위해 서버로 HTTP 요청을 전송하고, 서버는 이를 해석하여 정적 자원에 대한 요청일 경우 자원을 반환해주고, 그렇지 않은 경우 CGI 프로그램을 실행시켜 해당 결과를 리턴해준다. 이때 서버는 CGI 프로그램에게 요청을 전달해주고, 결과를 전달받기 위한 파이프라인을 연결한다. 그래서 CGI 프로그램은 입력에 대한 서비스를 수행하고, 결과를 클라이언트에게 전달하기 위해 결과 페이지에 해당하는 MIME 타입의 컨텐츠데이터를 웹 서버와 연결된 파이프라인에 출력하여 서버에 전달한다. 서버는 파이프라인을 통해 CGI 프로그램에서 출력한 결과 페이지의 데이터를 읽어, HTTP 응답헤더를 생성하여 데이터를 함께 반환해준다.

 

 

자료 출처 http://blog.daum.net/question0921/1070

 


Servlet Container(서블릿 컨테이너)


서블릿 컨테이너는 서블릿을 이해했다면 쉽게 이해될 것이다. 한마디로,

서블릿을 관리해주는 컨테이너

 

라고 할 수 있다.

 

우리가 서버에 서블릿을 만들었다고 해서 스스로 작동하는 것이 아니고 서블릿을 관리해주는 것이 필요한데, 그러한 역할을 하는 것이 바로 서블릿 컨테이너 이다.

 

예를 들어,

서블릿이 어떠한 역할을 수행하는 정의서라고 보면,

서블릿 컨테이너는 그 정의서를 보고 수행한다고 볼 수 있다.

 

서블릿 컨테이너는 클라이언트의 요청(Request)을 받아주고 응답(Response)할 수 있게, 웹서버와 소켓으로 통신하며 대표적인 예로 톰캣(Tomcat)이 있다. 톰캣은 실제로 웹 서버와 통신하여 JSP(자바 서버 페이지)와 Servlet이 작동하는 환경을 제공해준다.

 

 

[Servlet Container 역할]

  1. 웹서버와의 통신 지원
서블릿 컨테이너는 서블릿과 웹서버가 손쉽게 통신할 수 있게 해준다. 일반적으로 우리는 소켓을 만들고 listen, 
accept 등을 해야하지만 서블릿 컨테이너는 이러한 기능을 API로 제공하여 복잡한 과정을 생략할 수 있게 해준다.
그래서 개발자가 서블릿에 구현해야 할 비지니스 로직에 대해서만 초점을 두게끔 도와준다.
 
  2. 서블릿 생명주기(Life Cycle) 관리 
서블릿 컨테이너는 서블릿의 탄생과 죽음을 관리한다. 서블릿 클래스를 로딩하여 인스턴스화하고, 
초기화 메소드를 호출하고, 요청이 들어오면 적절한 서블릿 메소드를 호출한다. 
또한 서블릿이 생명을 다 한 순간에는 적절하게 Garbage Collection(가비지 컬렉션)을 진행하여 편의를 제공한다.

 

  3. 멀티쓰레드 지원 및 관리 
서블릿 컨테이너는 요청이 올 때 마다 새로운 자바 쓰레드를 하나 생성하는데, HTTP 서비스 메소드를
실행하고 나면, 쓰레드는 자동으로 죽게된다. 원래는 쓰레드를 관리해야 하지만 서버가 다중 쓰레드를
생성 및 운영해주니 쓰레드의 안정성에 대해서 걱정하지 않아도 된다.

 

  4. 선언적인 보안 관리 
서블릿 컨테이너를 사용하면 개발자는 보안에 관련된 내용을 서블릿 또는 자바 클래스에 구현해 놓지 않아도 된다.
일반적으로 보안관리는 XML 배포 서술자에 다가 기록하므로, 보안에 대해 수정할 일이 생겨도 자바 소스 코드를 
수정하여 다시 컴파일 하지 않아도 보안관리가 가능하다.

 

 

위에서 서블릿 컨테이너는 서블릿의 생명주기를 관리한다고 적어놓았다.

 

그렇다면 이번에는 추가적으로 서블릿의 생명주기에 대해서 자세히 알아보자.

 

[ Servlet 생명주기 ]

 

 

 

  1. 클라이언트의 요청이 들어오면 컨테이너는 해당 서블릿이 메모리에 있는지 확인하고, 없을 경우 init()메소드를 호출하여 적재한다. init()메소드는 처음 한번만 실행되기 때문에, 서블릿의 쓰레드에서 공통적으로 사용해야하는 것이 있다면 오버라이딩하여 구현하면 된다. 실행 중 서블릿이 변경될 경우, 기존 서블릿을 파괴하고 init()을 통해 새로운 내용을 다시 메모리에 적재한다.
  2. init()이 호출된 후 클라이언트의 요청에 따라서 service()메소드를 통해 요청에 대한 응답이 doGet()가 doPost()로 분기된다. 이때 서블릿 컨테이너가 클라이언트의 요청이 오면 가장 먼저 처리하는 과정으로 생성된 HttpServletRequest, HttpServletResponse에 의해 request와 response객체가 제공된다.
  3. 컨테이너가 서블릿에 종료 요청을 하면 destroy()메소드가 호출되는데 마찬가지로 한번만 실행되며, 종료시에 처리해야하는 작업들은 destroy()메소드를 오버라이딩하여 구현하면 된다.

JSP(Java Server Page)


마지막 JSP에 대해서 알아보자! 위에 내용을 다 이해했다면 JSP는 어렵지 않을 것이다. 

 

JSP를 한마디로 정리하면,

Java 코드가 들어가 있는 HTML 코드

 

라고 할 수 있다.

 

서블릿은 자바 소스코드 속에 HTML코드가 들어가는 형태인데,

JSP는 이와 반대로 HTML 소스코드 속에 자바 소스코드가 들어가는 구조를 갖는 웹어플리케이션 프로그래밍 기술이다. HTML속에서 자바코드는 <% 소스코드 %> 또는 <%= 소스코드 =%>형태로 들어간다. 자바 소스코드로 작성된 이 부분은 웹 브라우저로 보내는 것이아니라 웹 서버에서 실행되는 부분이다. 웹 프로그래머가 소스코드를 수정 할 경우에도 디자인 부분을 제외하고 자바 소스코드만 수정하면 되기에 효율을 높여준다. 또한 컴파일과 같은 과정을 할 필요없이 JSP페이지를 작성하여웹 서버의 디렉토리에 추가만 하면 사용이 가능하다. 서블릿 규칙은 꽤나 복잡하기 때문에 JSP가 나오게 되었는데, JSP는 WAS(Web Application Server)에 의하여 서블릿 클래스로 변환하여 사용된다. 

 

[ JSP 동작 구조 ]

 

 

 

웹 서버가 사용자로부터 서블릿에 대한 요청을 받으면 서블릿컨테이너에 그 요청을 넘긴다. 요청을 받은 컨테이너는 HTTP Request와 HTTP Response 객체를 만들어, 이들을 통해 서블릿 doPost()나 doGet()메소드 중 하나를 호출한다. 만약 서블릿만 사용하여 사용자가 요청한 웹 페이지를 보여주려면 out 객체의 println 메소드를 사용하여 HTML 문서를 작성해야 하는데 이는 추가/수정을 어렵게 하고, 가독성도 떨어지기 때문에 JSP를 사용하여 비지니스 로직과 프레젠테이션 로직을 분리한다. 여기서 서블릿은 데이터의 입력, 수정 등에 대한 제어를 JSP에게 넘겨서 프레젠테이션 로직을 수행한 후 컨테이너에게 Response를 전달한다. 이렇게 만들어진 결과물은 사용자가 해당 페이지를 요청하면 컴파일이 되어 자바파일을 통해 .class 파일이 만들어지고, 두 로직이 결합되어 클래스화 되는것을 확인할 수 있다. 즉, out객체의 println 메소드를 사용해서 구현해야하는 번거로움을 JSP가 대신 수행해준다.

728x90

+ Recent posts