항상 사용자가 객체에 대해 어떻게 생각할지, 어떤 메소드가 우리의 객체를 사용하기 쉽게 할지가 가장 중요하다.
package com.in28minutes.oops.level2;
public class FanRunner {
public static void main(String[] args) {
// TODO Auto-generated method stub
//3.생성자에 맞는 값들을 넣어준다
Fan fan = new Fan("Manufacturer 1", 0.34567, "GREEN");
fan.switchOn();
fan.setSpeed((byte)5);
//8.이경우 switchoff인경우에도 speed가 5로 출력된다.
//4.현재 객체에 대한 상태를 출력해보자
System.out.println(fan);
//5.의도는 값을 출력하고자 하는 거였으나 com.in28minutes.oops.level2.Fan@7c30a502
//이런 정보가 나온다.
}
}
package com.in28minutes.oops.level2;
public class Fan {
//1.객체의 상태를 나타내는 변수
private String make;
private double radius;
private String color;
//7. 위의 세가지는 변하지 않는 변수지만 아래 두가지는 변할 수 있다.
private boolean isOn;
private byte speed;
//2.public이란 생성자를 만들었다. 그러나 이상태로는 디폴트 생성자가
//없기 때문에 에러가 나온다
public Fan(String make, double radius, String color) {
this.make = make;
this.radius = radius;
this.color = color;
}
public void switchOn() {
this.isOn = true;
setSpeed((byte)5); //디폴트 speed값 선언
}
public void switchoff() {
//9.전원이 꺼지면 속도도 0이 되야 하므로 속도를 0으로 만드는 식을 추가한다
this.isOn = false;
setSpeed((byte)0);
}
public void setSpeed(byte speed) {
this.speed = speed;
}
//6.전체 객체에 대해 스트링으로 상태를 나타낼 수 있게 설정했다.
@Override
public String toString() {
return String.format("make - %s, radius - %f,color - %s, ison - %b, speed - %d", make, radius, color, isOn,
speed);
}
}
package com.in28minutes.oops.level2;
public class RectangleRunner {
public static void main(String[] args) {
Rectangle rectangle = new Rectangle(12, 23);
System.out.println(rectangle);
rectangle.setLength(15);
System.out.println(rectangle);
}
}
package com.in28minutes.oops.level2;
public class Rectangle {
private int length;
private int width;
public Rectangle(int length, int width) {
this.length = length;
this.width = width;
}
public int getLength() {
return length;
}
public void setLength(int length) {
this.length = length;
}
public int getWidth() {
return width;
}
public void setWidth(int width) {
this.width = width;
}
public int area() {
return length * width;
}
public int perimeter() {
return 2 * (length + width);
}
// area와 perimeter는 메소드이기 때문에 ()를 붙여줘야 한다
@Override
public String toString() {
return String.format("length - %d width - %d area - %d perimeter - %d", length, width, area(), perimeter());
}
package com.in28minutes.oops.level2;
public class CustomerRunner {
public static void main(String[] args) {
Address homeAddress = new Address("line 1", "Hyderabad", "500035");
Customer customer = new Customer("Ranga", homeAddress);
//7.회사 주소를 추가하고 싶은 경우
Address workAddress = new Address("line 1 for work", "Hyderabad", "500035");
customer.setWorkaddress(workAddress);
System.out.println(customer);
//name - [Ranga] home address - [line 1 Hyderabad 500035] work address - [line 1 for work Hyderabad 500035]
}
}
package com.in28minutes.oops.level2;
public class Customer {
private String name;
//1.주소는 자체적으로 객체가 되거나 클래스가 될 수 있다. address에 컨트롤1 후 클래스를 만들자
private Address homeAddress;
private Address workAddress;
//3. 고겍에는 주소값이 포함되어 있다. 이것을 객체 구성 관계라고 한다.
//4.고객이라는 객체를 만들 때 주소가 필수라면 생성자에 포함해야한다. home은 필수라고 가정하자.
public Customer(String name, Address homeAddress) {
this.name = name;
this.homeAddress = homeAddress;
//5. 이름은 한 번 만들면 수정이 불가능하고 주소는 변동이 가능하다고 가정하고 게터 세터를 불러올 것
}
public Address getHomeaddress() {
return homeAddress;
}
public void setHomeaddress(Address homeaddress) {
this.homeAddress = homeaddress;
}
public Address getWorkaddress() {
return workAddress;
}
public void setWorkaddress(Address workaddress) {
this.workAddress = workaddress;
}
public String toString() {
return String.format("name - [%s] home address - [%s] work address - [%s]", name, homeAddress, workAddress);
}
}
package com.in28minutes.oops.level2;
public class Address {
//2. 주소는 도시,우편번호 등 복잡해질 수 있는 값이다.
private String line1;
private String city;
private String zip;
//6. 주소를 어떻게 만들지 생각하고 모든 항목이 필수 사항이라고 가정해보자.
//알트 쉬프트 s 로 Constructor using field즉 생성자를 만들자.
public Address(String line1, String city, String zip) {
super();
this.line1 = line1;
this.city = city;
this.zip = zip;
}
public String toString() {
return line1 + " " + city + " " + zip;
}
}
만약 우리가 아무 생성자도 제공하지 않으면, 함축적으로 상위 클래스에서 인수 생성자가 호출 되지 않는다. 그래서 인수가 없는 Person 생성자가 있다면, 그것이 Student와 Employee에서 호출되는 것이다. 만약 Student와 Employee클래스들이 생성자가 없고 직접적으로 생성자를 인수와 함께 상위 클래스에서 제공한다면 우리는 이 생성자들을 양쪽 하위 클래스에서 호출해야 한다. 우리는 super(name)을 통해 호출했다. 우리가 super(name)을 통해 직접적으로 호출하지 않는다면 첫번째 줄은 super()란 것으로 불리는 것을 보았다. 그리고 우리 상황에서는 컴파일 오류가 발생했는데 왜냐하면 거기에는 기본 생성자가 Person 클래스 안에 없었기 때문이다(이름과 직책을 가진 것을 원했으므로). 따라서 컴파일하게 하려면 super(name)을 호출해야 했다
중요한 점은 하위 클래스 생성자는 상위 생성자가 무조건 정의되어야 한다는 점이다.
package com.in28minutes.oops.level2.inheritance;
public class Person {
private String name;
private String email;
private String phoneNumber;
//1. student 클래스에는 person클래스보다 조금 더 자세한 정보를 담고 싶다.
//6. 이 클래스의 생성자를 만들자 generate using field로 만드는데 이름은 필수이기 때문에 이름만 선택했다.
//10.이 부분을 지우고 저장하면 프로그램은 자동으로 진행되지만 이 생성자를 추가하면 student 와 employee에컴파일 오류가 나온다.
// public Person(String name) {
// super();
// this.name = name;
// }
//11.이해를 위해 단순한 생성자를 만들어보자.
public Person(String name) {
System.out.println("Person Constructor");
this.name = name;
}
//15.만약 이렇게 생성자를 문자열 이름으로 바꾸면
// public Person() {
// System.out.println("Person Constructor");
// }
public String getName() {
return name;
}
//7.이름을 담은 생성자가 있기 때문에 setName을 지우겠다
// public void setName(String name) {
// this.name = name;
// }
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public String getPhoneNumber() {
return phoneNumber;
}
public void setPhoneNumber(String phoneNumber) {
this.phoneNumber = phoneNumber;
}
@Override
public String toString() {
return name + "#" + email + "#" + phoneNumber;
}
}
package com.in28minutes.oops.level2.inheritance;
public class StudentWithoutInheritance {
private String name;
private String email;
private String phoneNumber;
private String college;
private int year;
//2.복사 후 person과 동일한 세부내용을 가지고 있지만 다른 내용도 추가하고싶다
//person과 비슷한 부분이 많은데 이런 식의 복사 붙여넣기는 좋지 않다.여기서 상속이 등장하는데
//상속은 person클래스에 있는 코드들을 student클래스에서 사용하게 해주지만 가져가고 싶은 것만 고를 수 있다.
public String getName() {
return name;
}
public String getCollege() {
return college;
}
public void setCollege(String college) {
this.college = college;
}
public int getYear() {
return year;
}
public void setYear(int year) {
this.year = year;
}
public void setName(String name) {
this.name = name;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public String getPhoneNumber() {
return phoneNumber;
}
public void setPhoneNumber(String phoneNumber) {
this.phoneNumber = phoneNumber;
}
}
package com.in28minutes.oops.level2.inheritance;
public class Student extends Person {
//3. person에 있는 모든 기능,요소,멤버 변수등을 가져오고 싶다.
//+새로운 작업도 가능하다.
private String collegeName;
private int year;
//18.여기서도 Employee와 같은 문제를 해결해보자 Person이 정의되지 않아서 Person을 호출할 수 없다는 것이다
public Student(String name, String collegeName) {
super(name);
this.collegeName = collegeName;
}
public String getCollegeName() {
return collegeName;
}
public void setCollegeName(String collegeName) {
this.collegeName = collegeName;
}
public int getYear() {
return year;
}
public void setYear(int year) {
this.year = year;
}
}
package com.in28minutes.oops.level2.inheritance;
public class StudentRunner {
public static void main(String[] args) {
// Student student = new Student();
//4.student.을 입력했을 때 Student클래스에 있는 모든 메소드가 보인다. 추가로 Person코드에 있는 메소드도 확인 가능
//student에는 name email 이런 것들이 없는데도 Person에서 상속받았기 때문에 가능한 것
// student.setName("Ranga");
// student.setEmail("in28minutes@gmail.com");
// Person person = new Person();
//13.Employee생성자를 호출하자마자 여기서 Employee 생성자를 부른다.
//19.employee에 이름과 직책을 넣어줘야 하기 때문에 넣어준다
Employee employee = new Employee("Ranga", "Programmer Analyst");
//8.setName을 지웠기 때문에 오류가 뜬다.
// employee.setName("Ranga");
employee.setEmail("ranga@in28minutes@gmail.com");
employee.setPhoneNumber("123-456-7890");
employee.setEmployeeGrade('A');
employee.setTitle("Programmer Analyst");
System.out.print(employee);
}
}
package com.in28minutes.oops.level2.inheritance;
import java.math.BigDecimal;
//9.Employee에 오류가 나는 이유는 함축적인 상위 생성자 Person()이 기본 생성자로 정의되어 있지 않아서이다.
public class Employee extends Person {
private String title;
private String employerName;
private char employeeGrade;
private BigDecimal salary;
public String getTitle() {
return title;
}
//12.여기서도 간단한 생성자를 만들어보자. 만든 후 studentrunner를 컴파일하면 person이 먼저나오고 그 다음에 employee가 나오는 걸 알 수 있다.
//14.Employee생성자는 함축적으로 super를 호출하게 된다. 직접 추가해도 되지만 그렇게 하지 않으면 자바 컴파일러가 자동으로 이 상위클래스를 추가하게 된다.
//하위 클래스에서 생성자를 만들 때마다 첫번째 줄에서는 자동으로 상위 생성자가 발동된다. 그래서 person 생성자가 먼저 보이는 것이다.
// public Employee() {
//16.employee부분에 함축적 상위 생성자가 정의되지 않았다는 오류가 나온다. 즉 상위를 호출하려하는데 아무것도 없다는 뜻이다.
// super();
// System.out.println("Employee Constructor");
// }
//17.이를 Person을 개방형으로 만들고 기본 생성자를 만들어 주는 식으로 해결할 수 있다. 그러나 우리는 이름 없이 Person 클래스가 만들어지는 것이 싫다.
// public Employee() {} 우리는 이름과 직책을 필수로 하고싶다.
public Employee(String name, String title) {// 이렇게 하면 함축적 상위 생성자가 정의되지 않았다는 오류가 나온다
super(name); // 상위클래서 생성자를 이름과 함께 부를 수 있다.
this.title = title;
System.out.println("Employee Constructor");
}
public void setTitle(String title) {
this.title = title;
}
public String getEmployerName() {
return employerName;
}
public void setEmployerName(String employerName) {
this.employerName = employerName;
}
public char getEmployeeGrade() {
return employeeGrade;
}
public void setEmployeeGrade(char employeeGrade) {
this.employeeGrade = employeeGrade;
}
public BigDecimal getSalary() {
return salary;
}
public void setSalary(BigDecimal salary) {
this.salary = salary;
}
//5.상위클래스에서 getemail을 가져오기 위해 super.을 이용한다
//toString은 object객체에 있는 것고 object객체는 항상 superclass 이기 떄문에
//System.out.println(student) 출력시 student.toString이랑 같은 것이라고 생각하면 된다.
//즉 객체를 보내서 출력하려고 할 때마다 toString메소드가 입력된다
//출력 형태를 바꾸기위해서 기존 object객체가 가지고 잇는 toString메소드를 바꾼 것이다.
@Override
// super.이란 상위클래스에서 값을 가져올 수 있게 해준다. 상위 클래스 메소드를 호출하는 것.
//아래처럼 하면 person클래스에 있는 toString 즉
//public String toString() {
// return name + "#" + email + "#" + phoneNumber;
//} + # + title ...처럼 출력된다.
public String toString() {
return super.toString() + "#" + title + "#" + employerName + "#" + employeeGrade + "#" + getEmail();
}
}
package com.in28minutes.oops.level2.inheritance;
//1.추상적 클래스로 만들고 싶기 때문에 abstract를 추가해준다
public abstract class AbstractReceipe {
public void execute() {
//2.우리는 아래것들을 실행함에 있어 무엇이 연관되어 있는지 정하고 싶지 않다.
getReady();
doTheDish();
cleanup();
}
abstract void getReady();
abstract void doTheDish();
abstract void cleanup();
}
package com.in28minutes.oops.level2.inheritance;
//3.Recipe1아리에 필수적으로 상속된 추상메소드들을 적용해야 한다고 나온다. 컨트롤1, 비적용된 메소드 추가해준다
public class Recipe1 extends AbstractReceipe{
@Override
void getReady() {
System.out.println("Get the raw materials");
System.out.println("Get the utensils");
}
@Override
void doTheDish() {
System.out.println("Prepare the dish");
}
@Override
void cleanup() {
System.out.println("Cleanup the utensils");
}
}
package com.in28minutes.oops.level2.inheritance;
public class RecipeRunner {
public static void main(String[] args) {
Recipe1 recipe = new Recipe1();
//4.execute의 정의는 AbstractReceipe에의해 적용되고 있다. AbstractReceipe 각단계들의
//정의는 Recipe1 클래스에의해 제공되고 있다.
recipe.execute();
RecipewithMicrowave recipeWithMicrowave = new RecipewithMicrowave();
recipeWithMicrowave.execute();
}
}
package com.in28minutes.oops.level2.inheritance;
//5.전자레인지를 쓰는 레시피를 만들어보자. Recipe1과는 각각의 단계를 다르게 정의하고 있다
public class RecipewithMicrowave extends AbstractReceipe{
@Override
void getReady() {
System.out.println("Get the raw materials");
System.out.println("Switch on the microwave");
}
@Override
void doTheDish() {
System.out.println("get stuff ready");
System.out.println("Put it in the microwave");
}
@Override
void cleanup() {
System.out.println("Cleanup the utensils");
System.out.println("Switch off the microwave");
}
}
package com.in28minutes.oops.level2.interfaces;
public interface GamingConsole {
//1.버튼 네개가 있다고 가정해보자
public void up();
public void down();
public void left();
public void right();
}
package com.in28minutes.oops.level2.interfaces;
//2.우리는 여기에 GamingConsole을 적용하고 싶은 것이다. 마리오부분에 에러에 컨트롤1 후 메소드 추가해준다.
public class MarioGame implements GamingConsole {
@Override
public void up() {
System.out.println("Jump");
}
@Override
public void down() {
System.out.println("Goes into a hole");
}
@Override
public void left() {
}
@Override
public void right() {
System.out.println("Go Forwards");
}
}
package com.in28minutes.oops.level2.interfaces;
public class GameRunner {
public static void main(String[] args) {
// MarioGame game = new MarioGame();
// ChessGame game = new ChessGame();
//4. 이렇게 하면 move piece up 같은 ChessGame에 입력된대로 나온다. 하지만 우리는 이제 GamingConsole을 사용할 수 있다
GamingConsole game = new MarioGame();
GamingConsole game = new ChessGame();
//5.뒤에 부분을 바꿔주는 것만으로 다른 구현이 되는 셈이다
game.up();
game.down();
game.left();
game.right();
}
}
package com.in28minutes.oops.level2.interfaces;
//3. 인터페이스의 장점은 하나에 여러 적용법이 있을 수 있다는 것이다
public class ChessGame implements GamingConsole {
@Override
public void up() {
System.out.println("Move piece up");
}
@Override
public void down() {
System.out.println("Move piece down");
}
@Override
public void left() {
System.out.println("Move piece left");
}
@Override
public void right() {
System.out.println("Move piece right");
}
}