Goal : 구성이 무엇인지 알아보고, 코드에서는 어떻게 구현되는지 알아본다.
요구사항
Fan Class
- State (Member Variables)
- make
- radius;
- color;
- isOn;
- speed;
- Constructors
- Fan(String make, double radius, String color)
- Behaviour(Member Methods)
- void switchOn()
- void switchOff()
- void setSpeed()
- String toString() using String.format method
state, constructor, methods
Fan Class
package com.in28mins.oop;
public class Fan {
//state (3 important things when you create a fan)
private String make;
private double radius;
private String color;
// less important than 3 things above when you create a fan
private boolean isOn;
private byte speed; //0 to 5
//creation - this would ensure that anybody who's creating Fan objet would pass in this value
Fan(String make, double radius, String color) {
this.make = make;
this.radius = radius;
this.color = color;
}
public void isOn(boolean isOn){
this.isOn = isOn;
}
public void switchOn() {
this.isOn = true;
setSpeed((byte) 5);
}
public void switchOff() {
this.isOn = false;
setSpeed((byte) 0);
}
public void setSpeed(byte speed) {
this.speed = speed;
}
//print the state
public String toString() {
return String.format("make - %s, radius -%f, color - %s, isOn - %b, speed - %d",
make, radius, color, isOn, speed);
}
}
생성자를 만들 때 왜 String make, double radius, String color만 파라미터로 받을까? 이유인 즉, 새로운 인스턴스를 이 클래스를 통해 만들 때 이 세가지는 필수적인 반면 boolean isOn 와 int speed는 객체가 생성될 때 꼭 필요한 요소가 아니기 때문이다.
Fan Runner Class
package com.in28mins.oop;
public class FanRunner {
public static void main(String[] args){
Fan fan = new Fan("Manufacturer 1", 0.34567, "GREEN");
//fan.isOn(false);
fan.switchOn();
System.out.println(fan);
fan.switchOff();
System.out.println(fan);
}
}
결과
make - Manufacturer 1, radius -0.345670, color - GREEN, isOn - true, speed - 5
make - Manufacturer 1, radius -0.345670, color - GREEN, isOn - false, speed - 0
the important this to realized is these are not just getters and setters
typically, when people start thinking about objects, the only method that they would expose from a specific object is getters and setters related to that. that's not really good practice.
you need to start thinking about how a consumer would be using your objects and create methods which make it easy to use your objects.
what we are trying to do is to apply what we have learned about designing a class. we need to think about the state, how do you want to allow the creation of the object, and also we would want to think about what is the behaviour you would want to allow
**Most of the times, you are the consumer of your obejcts. make sure you design them well!!
----------------
obejct안의 object
However, state of object can get much more complex that that!! you can have an object inside another object
위의 예제에서 변수 값을 단순 string, int, double의 자료형을 받았다. 만약 다른 클래스의 오브젝트를 가지고 오고 싶다면?!
Customer Class
package com.in28mins.oop;
public class Customer {
//state
private String name;
private Address homeAddress;
private Address workAddress;
//creating
Customer(String name, Address homeAddress){
this.name = name;
this.homeAddress = homeAddress;
}
public Address getWorkAddress() {
return workAddress;
}
public void setWorkAddress(Address workAddress) {
this.workAddress = workAddress;
}
public Address getHomeAddress() {
return homeAddress;
}
public void setHomeAddress(Address homeAddress) {
this.homeAddress = homeAddress;
}
//print the state
public String toString() {
return String.format("name - %s, homeAddress - %s , workAddress - %s",
name, homeAddress, workAddress);
}
}
**
1. 클래스를 만들때, 가장 중요한 점은 관련이 있는 다른 오브젝틀 간의 '관계'이다.
여기서는 Customer는 Address를 포함한다. ( has a relationship) Cumtomer has a Address
2. 그리고, 다시 오브젝트의 구조를 생각해보라. 고객 클래스를 생성할 때 이름과 자택주소는 필수인가? 그렇다면 생성자의 파라미터로 포함한다. 아니라면? 포함하지 않는다.
3. 다음 '고객의 관점으로' 생각하고, 우리는 그들에게 무엇을 허용하고 무엇을 허용하지 않을 것인가?
4. 그렇게 멤버변수, 생성자, 메소드를 생성하고 나면 도출된 결론은 다음과 같다.
customer 인스턴스를 생성하는 누구든 이름과 자택주소를 이용하여 생성할 수 있고, 자택 주소가 변경되거나 직장주소가 추가/변경 시에는 setHomeAddress(), setWorkAddress()를 사용하면 된다.
** oop에서 중요한 것은 우리가 oop에 접근하는 방식이다. 첫번째로는 클래스가 결정되면, 얼마나 개별적인 클래스가 구성될 수 있는지를 보고 구성을 결정할 것이다. 위의 예제에서는 우리는 고객이 두개의 주소(자택주소, 직장주소)를 갖기로 했으며 그것이 '구성'이다.
그 다음은 객체의 생성 시에 어떤 것을 허용할 것지 (생성자)를 결정하고, 그 후에 관련된 각개의 실행을 깊이 생각해보는 것, 그것이 oop thinking 이다.
so when we design our classess, one of the important things that i would start with is the relatioship between the different objects that are involved
here, Customer contains an Address
when we design our construction of the object, we need to start thinking about more detatils
when you create a Customer, is homeAddress mandatory? if it is, then I would include it in the constructor. If it's not, I would not
we would also think about what are the operations that we'd need to elaborate. so, for a customer, what are the operations that you would want to allow?
so now, somebody who creates a Customer can create it with a name and a home address, and when the home address changes, they can do
setHomeAdress() and if they want to add in a work address, they can actually say setWorkAddress() as well.
the imporatant thing about oop is the way we are approaching object oriented programming
so first thing is we would decide the classes, then we would decide the composition, how each class is composed
over here, we decided the customer would have two instances of the address class, that's called Composition
and then we would decide about how you'd want to allow creation of the objects
after that, you'd start thinking about the different operations that are involved
the focus behind these steps has been to get you initiated with oop thinking
Address Class
package com.in28mins.oop;
public class Address {
private String line1;
private String city;
private String zip;
//creation
public Address(String line1, String city, String zip) {
this.line1 = line1;
this.city = city;
this.zip = zip;
}
public String toString(){
return line1 +" " + city + " "+zip;
}
}
상대적으로 필수적이지 않은 것은 세터를 통해서 변경/추가를 할 수 있다.
위의 예제에서는 line1, city, zip이 필수적이라고 가정했고, 이들이 수정이 가능하도록 허용하고 싶을 수 있겠지만,
나(강사쌤)는 수정을 허용하고 싶지 않음으로 세터를 생성하지 않겠다. 만약 누군가 주소를 업데이트하기를 원한다면 새로운 주소 오브젝트를 생성하고 그 새로운 주소를 customer에게 할당해야한다.
what are not essentials, we would probably create a settters for that.
in this example, we assumed everything is important, now, you'd want to allow modifications of a line1, city, or zip
i think i would not want to allow modifications, if somebody wants to update the address, they can create a new address object and set it as the address to the customer
CustomerRunner Class
package com.in28mins.oop;
public class CustomerRunner {
public static void main(String[] args){
Address homeAdress = new Address("flat 1004", "Seoul", "111-222");
Customer customer = new Customer("rosie", homeAdress);
System.out.println(customer);
Address workAdress = new Address("work 999", "Seoul", "111-333");
customer.setWorkAddress(workAdress);
System.out.println(customer);
}
}
결과
name - rosie, homeAddress - flat 1004 Seoul 111-222 , workAddress - null
name - rosie, homeAddress - flat 1004 Seoul 111-222 , workAddress - work 999 Seoul 111-333
필수가 아니었던 직장 주소는 최초 출력시에는 null로 표현이 되고, 이후 setWorkAddress()를 통해 추가가 되고 난 이후에 출력이 되었다.
obejct안의 ArrayList
요구사항
- Book class
- id
- name
- author
- addReview(Review)
- Review class
- id
- description
- rate
Book Class
package com.in28mins.oop;
import java.util.ArrayList;
public class Book {
private int id;
private String name;
private String author;
private ArrayList<Review> reviews = new ArrayList<>();
public Book(int id, String name, String author) {
this.id = id;
this.name = name;
this.author = author;
}
public void addReview(Review review){
this.reviews.add(review);
}
public String toString(){
return String.format("id =%d ,name=%s, author =%s, Reviews = %s", id, name, author, reviews);
}
}
- Book은 Review를 포함한다.
- 리뷰는 여러개일 일 수 있으므로 ArrayList로 생성한다.
- id, author, name은 book class의 필수 정보이므로 생성자의 파라미터로 받지만, review는 필수 값이 아님으로 제외한다.
- 책을 읽고 나서 리뷰를 작성할 수 있으니, addReview()라는 메소드를 생성하여 추가할 수 있다
- addReview()라는 메소드는 review class를 파라미터로 가지는데, id, description, rate가 필수 요소이다.
Review Class
package com.in28mins.oop;
public class Review {
private int id;
private String description;
private int rate;
public Review(int id, String description, int rate) {
this.id = id;
this.description = description;
this.rate = rate;
}
public String toString(){
return id+ " "+ description +" "+ rate;
}
}
BookRunner Class
package com.in28mins.oop;
public class BookRunner {
public static void main(String[] args){
Book book = new Book(1,"java with rosie","rosie kim");
book.addReview(new Review(10, "excellent",10));
book.addReview(new Review(11, "lovely",9));
System.out.println(book);
}
}
결과
id =1 , name=java with rosie , author =rosie kim ,Reviews = [10 excellent 10, 11 lovely 9]
정리
구성이란 한 클래스의 멤버변수로 다른 클래스 타입의 참조 변수를 선언하는 것을 의미한다.
- has a relationship
- 코드 재사용
'객체지향이란 이런 것이다'를 이번 구성을 정리하면서 배운 것 같다. 클래스를 디자인할 때 oop를 지향하면서 설계하고 프로그래밍을 하는지 또 내가 이 클래스의 소비자라는 관점으로 어떤 것이 허용되고 허용되지 않을지 등등..!!
국내에도 훌륭한 자바 강의는 많지만 내가 이 강의를 선택한 건 주언어가 영어인 점이었다. 이 강의를 통해 영어 실력을 늘리겠다! 이 관점보다는 언어의 구조가 문화, 정치, 경제와 더불어 관념, 생각, 설명하는 방식 등 사소한 것 조차도 무수한 영향을 미치므로 영어나 타언어가 모국어인 분들의 설명과 접근 방식이 더 궁금했기 때문이다. 종종 나는 한글을 읽고도 도대체 무슨 소리인지 소리 내어서 읽어본 적이 한 두번이 아니었으므로.. 시간이 더 걸릴지라도 지금 이 패턴으로 하다보면 나에게 다른 방식의 관점이 키워질 것이라고 믿고. 가보겠다! 물론 내가 해석하는 언어가 틀릴지언정 공부를 하면서 문맥파악에 더 잘 알게 되겠지. 그때마다 틈틈히 수정해야겠다!
@ The teacher Mr. Ranga 강의를 참조하고 있습니다.
'JAVA > 객체지향의 원리' 카테고리의 다른 글
[OOP] interface / 인터페이스 (0) | 2022.09.07 |
---|---|
[OOP] abstract / 추상화 (0) | 2022.09.05 |
[OOP] Inheritance / 상속 (0) | 2022.08.19 |
[OOP] Constructor / 생성자 (0) | 2022.08.09 |
[OOP] Encapsulation / 캡슐화 (0) | 2022.07.31 |