Java_객체지향프로그래밍3

5w31892p·2022년 11월 21일
0

Java_실시간

목록 보기
3/7

📜 Java

:: ✍ 실시간 강의 | 객체지향 프로그래밍

:: 객체지향 프로그래밍 ( Object-Oriented Programming, OOP )

  • 컴퓨터 프로그램을 명령어의 목록으로 보는 시각에서 벗어나 여러개의 독립된 단위
    • 즉, 객체들의 모임으로 파악하고자 하는 것
  • 유연하고 변경이 쉽게 만듦
    • 대규모 sw개발에 많이 사용

:: 유연하고 변경이 쉽게

다형성

  • 클라이언트(요청자)를 변경하지 않고, 내부 기능을 변경 가능
// status의 기능을 변경하고싶다.
// status를 "off" 값을 반환한다.
class Plug {
    public void on() {}
    public void off() {}
}

interface InternetOfThings {
    String status();
}

class SmartPlug extends Plug implements InternetOfThings {
     public String status() {
         ...
         ...
         return "ok";
     }
}

class OffPlug extends Plug implements InternetOfThings {
		public String status() {
        return "off";
    }
}


SmartPlug sp = new SmartPlug();
sp.on();
sp.off();
OffPlug op = new OffPlug();

Plug p = sp;
p.on();
p.stop();

InternetOfThings iot = sp; -> InternetOfThings iot = op

iot.status(); // sp -> ok, op -> off
  • 유비쿼터스 언어 = 언어의 합을 맞추는 것
  • 솔리드 = 어떻게 낮은비용으로 교체하나?
  • 의미있는 메소드를 통해서만 건드릴 수 있게 단순 set으로 쓰지말고
    set이라고 하면 구체적으로 어떤 행동인지 알기가 힘드니까 구체적으로 명시

:: SOLID

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

  • 한 클래스는 하나의 책임만 가져야 함
  • 하나의 책임은 클수도 있고, 작을 수도 있음
  • 하나의 책임의 기준은 변경!
    • 변경이 발생하였을 때, 변경해야 될 부분이 적으면, 단일 책임 원칙을 잘 따른 것
    • 클래스를 변경해야하는 이유가 오직 하나여야 함
  • 예) 결제 버튼의 위치가 변경 되었지만, 결제 기능에 대한 영향은 없다.
class Galaxy {
  private String serialNumber;
  private String cpu;
  private String memory;
  private int battery;
  private double weight;
}

// serialNumber는 고유정보 -> 변화 요소가 아님.
// cpu, memory, battery, weight는 특성 정보로 변경이 발생할 수 있음.
// 특성 정보에 변화가 발생하면, Galaxy 을 변화 시켜야 되는 부담이 발생함.


// 스펙만 관리
class GalaxySpec {
  private String cpu;
  private String memory;
  private int battery;
  private double weight;
}

class Galaxy {
   private String serialNumber;
	 private GalaxySpec spec;
   public Galaxy(String serialNumber, GalaxySpec spec) {
      this.serialNumber = serialNumber;
      this.spec = spec;
   }
}

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

  • 확장에는 열려있으나 변경에는 닫혀있어야 함
  • 변경을 위한 비용은 줄이고, 확장을 위한 비용은 극대화 해야함
  • 객체지향의 장점을 극대화하는 아주 유용한 원리(feat, 다형성)
  • 템플릿 메소드 패턴 찾아볼 것 → OCP원칙의 좋은 예
class Galaxy {
  private String serialNumber;
  private String cpu;
  private String memory;
  private int battery;
  private double weight;
}
class GalaxySpec {
  private String cpu;
  private String memory;
  private int battery;
  private double weight;
}

class Galaxy {
   private String serialNumber;
	 private GalaxySpec spec;
   public Galaxy(String serialNumber, GalaxySpec spec) {
      this.serialNumber = serialNumber;
      this.spec = spec;
   }
}


class IPhone {
  private String serialNumber;
  private String cpu;
  private String memory;
  private int battery;
  private double weight;
}
class IPhoneSpec {
  private String cpu;
  private String memory;
  private int battery;
  private double weight;
}

class IPhone {
   private String serialNumber;
	 private IPhoneSpec spec;
   public IPhone(String serialNumber, IPhoneSpec spec) {
      this.serialNumber = serialNumber;
      this.spec = spec;
   }
}

class Shaomi {
  private String serialNumber;
  private String cpu;
  private String memory;
  private int battery;
  private double weight;
}
class ShaomiSpec {
  private String cpu;
  private String memory;
  private int battery;
  private double weight;
}

class Shaomi {
   private String serialNumber;
	 private ShaomiSpec spec;
   public IPhone(String serialNumber, IPhoneSpec spec) {
      this.serialNumber = serialNumber;
      this.spec = spec;
   }
}

// 갤럭시 외에 새로운 핸드폰들이 생겨난다면?
// 추상화 작업을 통해서, 공통화 하자.
// 새로운 핸드폰이 추가 되면서, 변경 될 수 있는 부분들을 분리시킴으로써, 코드 수정을 최소화하여, 결합도를 줄이고,응집도를 높혔다.


class Phone {
   private String serialNumber;
	 private PhoneSpec spec;
   public Phone(String serialNumber, PhoneSpec spec) {
      this.serialNumber = serialNumber;
      this.spec = spec;
   }
}

class PhoneSpec {
  private String cpu;
  private String memory;
  private int battery;
  private double weight;
}

class Galaxy extends Phone

class IPhone extends Phone

class 샤오미 extends Phone

class Sony extends Phone

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

  • 부모 객체와 이를 상속한 자식 객체가 있을 때 부모 객체를 호출하는 동작에서 자식 객체가 부모 객체를 완전히 대체할 수 있다는 원칙
  • 하위 타입(자식)은 언제나 자신의 상위 타입(부모)으로 교체할 수 있어야 함
  • 정확성을 깨뜨리면 안됨
  • 원칙을 지키지 않으면 , 자식클래스의 인스턴스를 파라미터로 전달 했을 때 메소드가 이상하게 작동 할 수 있음
    • 스피커 기능 중 볼륨 업은 소리를 키우는 기능이다. 하만카돈 스피커의 볼륨업은 소리를 줄이면 안된다. 소리가 작게 커지더라도 소리를 키워야한다. → 그래야 믿고 쓸 수 있다.
  • 부모클래스에 대해 작성된 단위테스트가 자식클래스에 대해서는 작동되지 않을 것
  • 상속을 잘 활용하고 있다면, 이미 LSP를 하고 있는 것
class Rectangle {
    private int width;
    private int height;

    public void setHeight(int height) {
        this.height = height;
    }

    public int getHeight() {
        return this.height;
    }

    public void setWidth(int width) {
        this.width = width;
    }

    public int getWidth() {
        return this.width;
    }

    public int getArea() {
        return this.width * this.height;
    }
}

class Square extends Rectangle {
    @Override
    public void setHeight(int value) {
        this.width = value;
        this.height = value;
    }

    @Override
    public void setWidth(int value) {
        this.width = value;
        this.height = value;
    }
}

public class Test {
   static void testLSP(Rectangle rectangle) {
         rectangle.setWidth(5);
         rectangle.setHeight(3);
         System.out.println(rectangle.getArea());
   }
}

public static void main(String[] args){
      Rectangle rectangle = new Rectangle();
      rectangle.setWidth(5);
      rectangle.setHeight(2);
      rectangle.getArea(); // 10

      Rectangle square = new Square();
      square.setWidth(5);
      square.setHeight(2);
      square.getArea(); // 25
      
      Test.testLSP(new Rectangle());
      Test.testLSP(new Square());
}

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

  • 클라이언트가 자신이 사용하지 않는 메서드에 의존하지 않아야 함
  • 특정 클라이언트를 위하여, 하나의 범용 인터페이스를 제공하는 것 보다 여러 개의 인터페이스를 제공하는 것이 나음
  • AS-IS
public interface Phone {
    void call(String phoneNumber);
    void pay(String cardName);
    void wirelessCharge();
}

public class Galaxy implements Phone {
    @Override
    public void call(String phoneNumber) {
         // ..
    }

    @Override
    public void pay(String cardName) {
        // ..
    }

    @Override
    public void wirelessCharge() {
        // ..
    }
}

public class IPhone implements Phone {
    @Override
    public void call(String phoneNumber) {
         // ..
    }

    @Override
    public void pay(String cardName) {
        // ..
    }

		@Override
    public void wirelessCharge() {
        // ..
    }
}

public class SkyPhone implements Phone {
    @Override
    public void call(String phoneNumber) {
         // ..
    }

    @Override
    public void pay(String cardName) {
        // ..
    }

		@Override
    public void wirelessCharge() {
         // 1. 가만히 냅눈다. - 극강 빌런
         // 2. System.out.println("사용하지 않음"); - 그나마 양호
         // 3. throw new NotSupporedException(); - 테스트코드에서
    }

}


public void main (String args[]) {

   Phone phone = new Galaxy();
   phone = new Galaxy();
   phone = new SkyPhone();



   
   phone.wirelessCharge();  // 1. 에러를 찾는데, 시간이 오래 걸린다. 이건 빌런의 소행이다.
}
  • TO-BE
public interface Phone {
    void call(String phoneNumber);
}

public interface WirelessCharge {
    void wirelessCharge();
}

public interface Payment{
    void pay(String cardName);
}

public class Galaxy implements Phone, WirelessCharge, Payment {
    @Override
    public void call(String phoneNumber) {
         // ..
    }

    @Override
    public void pay(String cardName) {
        // ..
    }

		@Override
    public void wirelessCharge() {
        // ..
    }

}

public class SkyPhone implements Phone {
    @Override
    public void call(String phoneNumber) {
         // ..
    }
}

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

  • 객체들 간의 협력 하는 과정에서 의존 관계가 형성
  • 의존관계 역전 원칙은 이러한 의존 관계를 맺을 때, 어떻게 하면 변화에 용이하게 대응할 수 있을 것인가에 대한 가이드 라인
  • 변하기 쉬운 것과 어려운 것을 구분해야 함
  • 변하기 쉬운 것
    • 구체적인 행동
      • 스마트폰으로 전화를 건다.
      • 공중전화로 전화를 건다.
      • 이메일을 발송한다.
      • 카카오톡 메시지를 전달한다.
  • 하기 어려운 것
    • 흐름이나 개념과 같은 추상적인 것
      • 전화를 건다
      • 메시지를 전달한다.
public interface Phone {
   void call(String phoneNumber);
}

public class SmartPhone implements Phone {
    @Override
    public void call(String phoneNumber) {
        System.out.println("스마트폰 : " + phoneNumber);
    }
}

public class PublicPhone implements Phone {
    @Override
    public void call(String phoneNumber) {
        System.out.println("공중 전화 : " + phoneNumber);
    }
}

public class InternetPhone implements Phone {
    @Override
    public void call(String phoneNumber) {
        System.out.println("인터넷 전화 : " + phoneNumber);
    }
}


public class Person {
  private Phone phone;
  
  public void setPhone(Phone phone) {
      this.phone = phone; // 폰이 계속 바뀜.
  }

  public void call(String phoneNumber) {
      phone.call(phoneNumber);
  }
}

public class Main {
	public static void main(String[] args) {
				Person person = new Person();
        person.setPhone(new SmartPhone());
        person.setPhone(new InternetPhone());



        // 코드 수정 X
        person.call("01012341234"); // 스마트폰 전화,
  }
}

0개의 댓글