객체지향 프로그래밍(OOP)
실 세계의 일들을 객체를 사용해서 모델링한다.
수납 공간은 파일 ( 클래스 파일 ) 이며
기능을 위주로 수납한 방식보다 데이터를 위주로 수납한 방식이 올바르다.
기능 위주 : class input 에 inputExam(){}, inputStudent(){}, inputOmok(){}
데이터 위주 : class Exam 에 inputExam(){}, sortExam(){}, printExam(){}
함수는 데이터를 사용하는데
왜냐하면 구조화된 데이터를 사용하는 함수 모듈의 독립성을 침해하는 문제를 해결 할 수 있기 때문이다.
함수는 외부의 수정에 절대 영향을 받아서는 안된다!
class Ellipse{
int x, y, w, h;
int color;
}
void draw(Ellipse ellipse){
print("......", ellipse,x);
ellipse.x + ellipse.y
}
Ellipse 데이터 / draw함수는 Elipse를 이용해서 그림을 그리는 함수다.
문제점 : 지역변수를 이용해 로직을 구현해서 외부에 있는 전역변수를 쓴 적이 없다.
외부에서 어떠한 변화가 있어도 문제가 없어야 하는데 구조화된 데이터 Ellipse의 x변수 이름을 바꾼다면 오류가 난다.
이 함수내에서 외부에 있는 전역변수를 손댄적이 없음에도 불구하고 구조화된 데이터를 쓰게되면 속성의 변화에 영향을 미쳐 오류를 발생한다.
해결책 :
1. 절대 변수명을 바꾸지 않는다.
2. 바꾸되 책임지고 전 코드를 뒤져 바꾼다.
3. 고쳤을 때 오류가 나는 함수들을 한 곳에 모아놓는다!
데이터 구조를 정의하고있는 위치에 Elipse 사용하는 함수들을 다 모은다. 한 곳에 모아둠으로써 프로그램 유지보수를 쉽게 한다.
데이터와 함수를 모아 하나의 영역에 함께 정의하는것을 캡슐이라고 한다
즉 캡슐의 가장 큰 특징은 데이터구조의 변화가 이 안에서만 발생하고 외부에서 발생하지 않는다.
캡슐화 : 데이터 구조와 함수를 하나의 영역에 모아 놓는 작업
캡슐 : 데이터 구조와 함수를 하나의 영역에 모아놓아 정의한 것
현재 코드는 이렇다.
public class Product {
String name;
int price;
int quantity;
}
public class Inventory {
Product[] products;
int current;
}
public class Program {
public static void main(String[] args) {
Inventory inventory = new Inventory();
inventory.products = new Product[5];
inventory.current=0;
int menu;
boolean keepLoop=true;
while(keepLoop) {
menu=inputMenu();
switch(menu)
{
case 1:
addInventory(inventory);
break;
case 2 :
// 기본 함수
displayInventory(inventory);
// overload 함수
displayInventory(inventory,2);
break;
case 3 :
System.out.println("종료");
keepLoop=false;
break;
default :
System.out.println("메뉴는 1~3번까지 입니다.");
}
}
}
private static int inputMenu() {
Scanner sc = new Scanner(System.in);
System.out.println("1.상품 입력 ");
System.out.println("2.재고 출력 ");
System.out.println("3.종료");
int menu=sc.nextInt();
return menu;
}
private static void addInventory(Inventory inventory) {
Scanner sc = new Scanner(System.in);
System.out.println("상품 입력");
String name;
int price, quantity;
System.out.printf("상품 이름 : ");
name=sc.next();
do {
System.out.print("가격 : ");
price=sc.nextInt();
if(price<0) {
System.out.println("가격은 0보다 커야합니다.");
}
}while(price<0);
do {
System.out.print("수량 : ");
quantity=sc.nextInt();
if(quantity<0) {
System.out.println("수량은 0보다 커야합니다.");
}
}while(quantity<0);
Product product = new Product();
product.name=name;
product.price=price;
product.quantity=quantity;
Product[] products = inventory.products;
int size = inventory.current;
if(products.length==size) {
// 1.크기가 3개정도 더 큰 새로운 배열을 생성
Product[] temp = new Product[size+3];
// 2.값을 이주
for( int i=0; i<size; i++) {
temp[i]=products[i];
}
// 3.inventory.products가 새로 만든 temp배열을 참조
inventory.products = temp;
}
products[size]=product;
inventory.current++;
}
private static void displayInventory(Inventory inventory) {
// 집중화 코드
displayInventory(inventory, inventory.current);
}
// overload
// 넘겨받은 size값만큼 출력
private static void displayInventory(Inventory inventory, int size) {
System.out.println("상품 출력");
for( int i=0; i<size; i++) {
Product product = inventory.products[i];
String name=product.name;
int price=product.price;
int quantity=product.quantity;
System.out.println( "상품 이름 : " + name);
System.out.println( "상품 가격 : " + price);
System.out.println( "상품 수량 : " + quantity);
}
}
}
1. 외부 로직에서 변수명을 바꾸면 Program클래스의 로직에도 영향을 미치게 된다. 이를 해결하기위해 해당 변수를 사용하는 함수들을 모아둔다.
public class Inventory {
Product[] products;
int current;
private static void addInventory(Inventory inventory) {
Scanner sc = new Scanner(System.in);
System.out.println("상품 입력");
String name;
int price, quantity;
System.out.printf("상품 이름 : ");
name=sc.next();
do {
System.out.print("가격 : ");
price=sc.nextInt();
if(price<0) {
System.out.println("가격은 0보다 커야합니다.");
}
}while(price<0);
do {
System.out.print("수량 : ");
quantity=sc.nextInt();
if(quantity<0) {
System.out.println("수량은 0보다 커야합니다.");
}
}while(quantity<0);
Product product = new Product();
product.name=name;
product.price=price;
product.quantity=quantity;
Product[] products = inventory.products;
int size = inventory.current;
if(products.length==size) {
// 1.크기가 3개정도 더 큰 새로운 배열을 생성
Product[] temp = new Product[size+3];
// 2.값을 이주
for( int i=0; i<size; i++) {
temp[i]=products[i];
}
// 3.inventory.products가 새로 만든 temp배열을 참조
inventory.products = temp;
}
products[size]=product;
inventory.current++;
}
private static void displayInventory(Inventory inventory) {
// 집중화 코드
displayInventory(inventory, inventory.current);
}
// overload
// 넘겨받은 size값만큼 출력
private static void displayInventory(Inventory inventory, int size) {
System.out.println("상품 출력");
for( int i=0; i<size; i++) {
Product product = inventory.products[i];
String name=product.name;
int price=product.price;
int quantity=product.quantity;
System.out.println( "상품 이름 : " + name);
System.out.println( "상품 가격 : " + price);
System.out.println( "상품 수량 : " + quantity);
}
}
}
2.
- 함수호출을 Inventory.addInventory(inventory); 형식으로 바꾼다.
- 원래 있던 초기값을 대입하는 초기화 함수로직을 Program에 새로 함수(Inventory.init(inventory);)를 만들어 모아놓는 규칙을 위반하지않게한다.
- 변수명이 바뀌어도 오류 범위가 Program에 한정된다. 만약 오류가 발생한다면 캡슐이 깨진것이다.
- Product[] products1; 으로 변수명이 바뀌어도 Program에서만 오류가 나는것을 확인하였다.
public class Program {
public static void main(String[] args) {
Inventory inventory = new Inventory();
int menu;
boolean keepLoop=true;
Inventory.init(inventory);
while(keepLoop) {
menu=inputMenu();
switch(menu)
{
case 1:
Inventory.addInventory(inventory);
break;
case 2 :
Inventory.displayInventory(inventory);
break;
case 3 :
System.out.println("종료");
keepLoop=false;
break;
default :
System.out.println("메뉴는 1~3번까지 입니다.");
}
}
}
private static int inputMenu() {
Scanner sc = new Scanner(System.in);
System.out.println("1.상품 입력 ");
System.out.println("2.재고 출력 ");
System.out.println("3.종료");
int menu=sc.nextInt();
return menu;
}
}
public class Inventory {
Product[] products;
int current;
static void addInventory(Inventory inventory) {
Scanner sc = new Scanner(System.in);
System.out.println("상품 입력");
String name;
int price, quantity;
System.out.printf("상품 이름 : ");
name=sc.next();
do {
System.out.print("가격 : ");
price=sc.nextInt();
if(price<0) {
System.out.println("가격은 0보다 커야합니다.");
}
}while(price<0);
do {
System.out.print("수량 : ");
quantity=sc.nextInt();
if(quantity<0) {
System.out.println("수량은 0보다 커야합니다.");
}
}while(quantity<0);
Product product = new Product();
product.name=name;
product.price=price;
product.quantity=quantity;
Product[] products = inventory.products;
int size = inventory.current;
if(products.length==size) {
// 1.크기가 3개정도 더 큰 새로운 배열을 생성
Product[] temp = new Product[size+3];
// 2.값을 이주
for( int i=0; i<size; i++) {
temp[i]=products[i];
}
// 3.inventory.products가 새로 만든 temp배열을 참조
inventory.products = temp;
}
products[size]=product;
inventory.current++;
}
static void displayInventory(Inventory inventory) {
// 집중화 코드
displayInventory(inventory, inventory.current);
}
// overload
// 넘겨받은 size값만큼 출력
static void displayInventory(Inventory inventory, int size) {
System.out.println("상품 출력");
for( int i=0; i<size; i++) {
Product product = inventory.products[i];
String name=product.name;
int price=product.price;
int quantity=product.quantity;
System.out.println( "상품 이름 : " + name);
System.out.println( "상품 가격 : " + price);
System.out.println( "상품 수량 : " + quantity);
}
}
public static void init(Inventory inventory) {
inventory.products = new Product[5];
inventory.current=0;
}
}
3. 인스턴스메서드 구현하기
void main(){
list = new ExamList();
ExamList.inputList(list);
ExamList.printList(list);
ExamList.svaeList(list);
}
void main(){
list = new ExamList();
list.inputList();
list.printList();
list.saveList();
}
list를 .을 통해 호출 = 객체를 통해서 호출
이러한 함수를 인스턴스 함수라고 명명한다.
list를 주체로 먼저 거론하고 list를 이용한 입력(), list를 이용한 출력(), list를 이용한 저장()을 사용한다.
단순하게 list의 데이터를 이용해서 입력받는 것이 아니라 책임까지 지니게한다. 즉 주체가 되게 함
list야.입력(해)이런식으 로 역할을 부여함 책임을 가진다. 인스턴스 메서드에서는 parameter로 전달 받는 것이 없기때문에 this를 이용한다.현재 호출되고 있는 객체가 this가 되는 것이다.
< static method 의 인스턴스 전달 vs instance method 의 인스턴스 전달 정리 >
static method : 고전적인 함수, 모든 값은 parameter를 통해 넘겨받고 일반적인 함수와 똑같이 사용한다.
instance method : 반드시 객체를 통해서만 호출( list. )됨, inputList()에서 따로 설명없이 list객체를 넘겨받는다.
예시
static method
- inputList함수에 static 과 매개변수 존재 ( static 일때 모든 데이터는 매개변로 전달되기 때문 )
- 매개변수를 통해 받은 객체로 .exams 와 .current 사용
public static void main(String[] args){
ExamList list = new ExamList();
ExamList.inputList(list);
}
class ExamList
{
public static void inputList(ExamList list)
{
list.exams[list.current] = new Exam();
}
instance method
- inputList메서드에 static 과 매개변수 없음
- 매개변수가 없기때문에 this로 .exams 와 .current 사용
- this는 생략가능하면 생략하는 것이 좋다.
public static void main(String[] args){
ExamList list = new ExamList();
list.inputList(); // instance method
}
class ExamList
{
public void inputList()
{
this.exams[this.current] = new Exam();
}
적용
public class Program {
public static void main(String[] args) {
Inventory inventory = new Inventory();
int menu;
boolean keepLoop=true;
inventory.init();
while(keepLoop) {
menu=inputMenu();
switch(menu)
{
case 1:
inventory.addInventory();
break;
case 2 :
inventory.displayInventory();
break;
case 3 :
System.out.println("종료");
keepLoop=false;
break;
default :
System.out.println("메뉴는 1~3번까지 입니다.");
}
}
}
private static int inputMenu() {
Scanner sc = new Scanner(System.in);
System.out.println("1.상품 입력 ");
System.out.println("2.재고 출력 ");
System.out.println("3.종료");
int menu=sc.nextInt();
return menu;
}
}
public class Inventory {
Product[] products;
int current;
void addInventory() {
Scanner sc = new Scanner(System.in);
System.out.println("상품 입력");
String name;
int price, quantity;
System.out.printf("상품 이름 : ");
name=sc.next();
do {
System.out.print("가격 : ");
price=sc.nextInt();
if(price<0) {
System.out.println("가격은 0보다 커야합니다.");
}
}while(price<0);
do {
System.out.print("수량 : ");
quantity=sc.nextInt();
if(quantity<0) {
System.out.println("수량은 0보다 커야합니다.");
}
}while(quantity<0);
Product product = new Product();
product.name=name;
product.price=price;
product.quantity=quantity;
Product[] products = this.products;
int size = this.current;
if(products.length==size) {
// 1.크기가 3개정도 더 큰 새로운 배열을 생성
Product[] temp = new Product[size+3];
// 2.값을 이주
for( int i=0; i<size; i++) {
temp[i]=products[i];
}
// 3.inventory.products가 새로 만든 temp배열을 참조
products = temp;
/*
이 부분 추가
temp 배열을 products에 할당했지만, 이는 지역 변수에 할당된 것이기 때문에 메소드가 종료되면서 사라지게 됩니다
따라서 this.products에 다시 할당
*/
this.products=products;
}
products[size]=product;
current++;
}
void displayInventory() {
// 집중화 코드
this.displayInventory(this.current);
}
// overload
// 넘겨받은 size값만큼 출력
void displayInventory(int size) {
System.out.println("상품 출력");
for( int i=0; i<size; i++) {
Product product = this.products[i];
String name=product.name;
int price=product.price;
int quantity=product.quantity;
System.out.println( "상품 이름 : " + name);
System.out.println( "상품 가격 : " + price);
System.out.println( "상품 수량 : " + quantity);
}
}
void init() {
this.products = new Product[5];
this.current=0;
}
}
4. 데이터구조는 private 서비스 기능은 pulbic으로 설정한다.
캡슐의 은닉성과 접근 지정자
데이터 구조라는 것에 대해서는 private
서비스를 해야할 것에 대해서는 public
private을 하지않으면 외부에서 접근이 가능하므로 캡슐이 언제든지 깨질 수 있다.
즉 캡슐이란 자기가 숨겨야할 내용에 대해서 은닉시킬수 있어야 한다.(은닉성)
이것을 가능하게 하는것은 private의 사용이다.
public class Inventory {
private Product[] products;
private int current;
public void addInventory() {
Scanner sc = new Scanner(System.in);
System.out.println("상품 입력");
String name;
int price, quantity;
System.out.printf("상품 이름 : ");
name=sc.next();
do {
System.out.print("가격 : ");
price=sc.nextInt();
if(price<0) {
System.out.println("가격은 0보다 커야합니다.");
}
}while(price<0);
do {
System.out.print("수량 : ");
quantity=sc.nextInt();
if(quantity<0) {
System.out.println("수량은 0보다 커야합니다.");
}
}while(quantity<0);
Product product = new Product();
product.name=name;
product.price=price;
product.quantity=quantity;
Product[] products = this.products;
int size = this.current;
if(products.length==size) {
// 1.크기가 3개정도 더 큰 새로운 배열을 생성
Product[] temp = new Product[size+3];
// 2.값을 이주
for( int i=0; i<size; i++) {
temp[i]=products[i];
}
// 3.inventory.products가 새로 만든 temp배열을 참조
products = temp;
/*
이 부분 추가
temp 배열을 products에 할당했지만, 이는 지역 변수에 할당된 것이기 때문에 메소드가 종료되면서 사라지게 됩니다
따라서 this.products에 다시 할당
*/
this.products=products;
}
products[size]=product;
current++;
}
public void displayInventory() {
// 집중화 코드
this.displayInventory(this.current);
}
// overload
// 넘겨받은 size값만큼 출력
public void displayInventory(int size) {
System.out.println("상품 출력");
for( int i=0; i<size; i++) {
Product product = this.products[i];
String name=product.name;
int price=product.price;
int quantity=product.quantity;
System.out.println( "상품 이름 : " + name);
System.out.println( "상품 가격 : " + price);
System.out.println( "상품 수량 : " + quantity);
}
}
public void init() {
this.products = new Product[5];
this.current=0;
}
}
참고자료출처(1-5) : https://www.youtube.com/watch?v=yGBmRdgc1Ic
'JAVA' 카테고리의 다른 글
UI코드 분리 하기 (0) | 2024.01.10 |
---|---|
Setter 대신 Overload 생성자 이용하기 (0) | 2024.01.09 |
Getter 와 Setter (0) | 2024.01.07 |
데이터 구조화 (0) | 2024.01.07 |
생성자 (0) | 2023.12.18 |