⌨️flutter

flutter OOP(객체지향 프로그래밍)

덩크냥 2024. 9. 5. 15:04

어느순간부터 내가 짠 코드들이 뭔가 뒤죽박죽이라는게 느껴졌다. 레거시 코드? 라고 한단다,!

 

회사프로젝트를 혼자서 개발하면서 방대한 코드들을 관리할 체계를 잡을 필요를 느꼈다.

UI와 데이터는 분리하는데 도메인 영역이 제대로 기준이 안잡혀있었다. 그러다가 mvvm 아키텍처를 적용하고 그에따라 명명법과 폴더구조 기준을 잡긴했다.

 

진짜작은프로젝트면 상관없는데 규모가 커지면 반드시 짚고 넘어가야할 부분인거같다.. 내 코드를 내가 파악하지 못하게 된다.

 

그런데 내가 익숙해져서 그냥 쓰는 코드들이 너무 많다. 내가 쓰는 이게 뭐인지는 잘 모르고 이것의 역할만 알뿐.,,

 

한번 기초로 돌아가자. 괜히 수많은 무협지나 만화에서 기본에 충실하라고 하는건 아닐거다.

 

오늘 되짚어 볼것들은

객체(Object), 클래스(Class), 상속(Inheritance), 캡슐화(Encapsulation), 다형성(Polymorphism)

추상화(Abstraction), 인터페이스(Interface), 의존성 주입(Dependency Injection), 합성(Composition), SOLID 원칙

옛날에 자바 해보면서 객체부터 인터페이스까지의 개념은 접해봤다. 다시 한번 복습 및 새로운것 정리 해보자.

 

물론 플러터 전체를 완전 정복하는건 현실적으로 어려울거다(아키텍쳐 엔진 레이어 뜯어본다거나,.). 그래도 내가 자주쓰는 것들은 뜯어볼 의지는 있다.

 

1. 먼저 객체.

객체는 설계도다! 라는 비유를 들었었다. 내가 이해한것중 가장 잘 이해됨. 설계도면을 갖고있으면 내가 그것 바탕으로 상품을 만들면 그게 그 유명한 '인스턴스화'이다. 

 

자동차를예시로

 

식별성(Identity) : 자 이제 현실세계에서 자동차 한대를 만들었다. 그리고 같은 설계도로 같은색과 같은 속력의 또다른 차 한대를 만들었다. 이 두대는 같은 차 일까?
No!

Car car1 = Car('red', 50);

Car car2 = Car('red', 50);

print(car1 == car2); // false다. 메모리상에서 각각 다른위치에 저장되며 고유 주소를 가짐

그렇기에 car1, car2 다르다는건 너무나 당연한 말.

상태(State) : 차 한대를 뽑을때 파란색으로 뽑으면 그차는 앞으로 새로페인트칠하지 않는이상 파란색이 유지가 된다. 이러한 변수들(color, speed)가 상태가 된다! 
 
행동(Behavior) : 한마디로 class내부의 메쏘드(함수)를 사용하겠다는것!
Car myCar = Car('blue', 60);
myCar.accelerate(); //얘가 속력을 10증가시키는 함수라면?
print(myCar.speed); // 70.  증가했다..
 
 
캡슐화(Encapsulation): 상태와 동작을 하나로 묶고, 외부에서 직접 접근하지 못하도록 보호. 데이터 무결성(데이터가 변하면 안됨)! 흔히 말하는 게터세터를 통해서 접근.

 

자 결국 객체를 쓰는 이유가 중요한거다.

보면 현실세계에 있는것들을 코드를 통해 설계한다.

(클래스를 설계도라고 생각했다시피) 여기서 말하는 설계는 데이터 모델링이다. 아직 모델설계가 익숙치 않다. 근데 항상 완벽주의가 있어서인지 공부부터 하고 만족스러울때쯤 실행에 옮기겠다!라는 어처구니없는 계획을 세운다.

일단 조금이라도 알았으면 행동으로 옮기자 왜냐면 나는 장기적으로 집중하기 힘들어 하기 때문이다. 쓱 빡 느낌으로다가 순간순간을 의미있게. 

 
회사 프로젝트를 하면서 a~z 내가 다 설계하고 개발하는 프로젝트를 맡았다. 모델설계 먼저 안하고 이제와서 땅을치고 후회중. 고칠게 많다!. 뭐 일단은 악으로 깡으로 릴리즈까지 완주하자 거의다 왔다 ><. 
 

 

2. 다음으로 class.

설계도이다! 

컨스트럭터(생산자) : 객체 만들때(인스턴스화 할때) 호출됨. 그래서 반드시 만족시켜줘야함! 세터와 비슷한데 초기에만 강제적으로 작동하는 애.. this를 통해 매치시켜줌!

 

 아그리고 
 변수들, 캡슐화 할려면 변수에 쉽게 접근이 안되어야한다 (private!!!!!) 그러면 변수이름앞에 _를 붙인다. 이러면 다른파일에서 접근 못하게 된다넹 신기.
 
 
 
3. Inheritance(상속).
 
부모 클래스: 상속 제공 클래스이다. 자식한테 물려줌. 흔히 쓰는 extends 에서 그 뒤에것이 부모 클래스임.
자식 클래스: 물려받는놈.
부모:Vehicle, 자식: Car

Car의 객체는 Vehicle의 변수 및 함수를 자유롭게 쓸 수 있음. 필요시 오버라이드해서 본인의것으로 커스텀!

자 이제 또하나

 

super: 얘는 부모의 constructor,method를 호출할때 씀.

잠깐, 우리가 stl 불러올때 꼭 항상 super을 컨스트럭터에 넣었었다.

오호, parameter가 key다.
stateless 클래스를 열어보면
key는 StatelessWidget클래스의 부모클래스인 Widget의 것이었다. 그위로 더 있나?
 

다행이 그 위로 DiagnosticableTree라는 클래스가 있지만 key 변수는 여기서 끝.

저 key라는 녀석이 무얼하는지 알아보자. 얘는 이번주 숙제.

설명이 있긴한데 지금 온 혈당스파이크 사라지면 읽겠다..

 

 근데 상속이 뎁스가 깊어지면 많이 헷갈릴거같다. 내가 직접 구축하는거면 많아봐야 3세대까지가 적절하지않을까,,?
 
 

4. Encapsulation(캡슐화)

앞에서 이미 짚고 넘어갔다. 패스
 

ㅇr...집중력 고갈,, 커피마시고 킵고잉

5. Polymorphism (다형성)

한자를 유추할수있다. 형태가 많은 특성..

크게 정적, 동적 두가지가 있다고 한다.

컴파일 시간 다형성(Compile-Time Polymorphism, 정적 다형성): 메소드 오버로딩! or 연산자 오버로딩!

(다트에서는 지원하지 않음.)

 

런타임 다형성(Runtime Polymorphism, 동적 다형성): 자식 클래스가 부모 클래스의 메소드를 재정의함으로써 객체에 따라 다르게 동작하게함. 다시말해서 이름은 그대로이되 자식이 부모의 것을 커스텀 한다는 뜻

 
 
 

6. Abstract(추상화)

우리가 자동차 내부 엔진까지 알아야하는가? 타이어가 뭔지 백미러는 깨끗한지 이정도는파악하지만 굳이 굳이 엔진의 오늘의 온도는? 이러지는 않는당.. 중요한건 외부와 직접작용하는 녀석들!

복잡성 감추기!

필요한 인터페이스만 노출!

느낌 왔다.

 폴리몰피즘이랑인접한 느낌.

동일인터페이스로 여러형태의 오브젝트 처리 가능.

지금까지 @override는 알아서 추가가 됐는데 왜 추가되는지 한번 되짚어보게 되니 참 기쁘다.

7. Interface(인터페이스)

클래스들이 반드시 구현해야 하는 메소드들의 집합!

나는 이걸 규격이라고 이해했다. 헷갈리거나 문제생기지 않도록 사용필수 요소를 강제하는것. 얘를 dart에서 실제로 직접구현한건 없었다. 다만 이 개념 자체가 required와 비슷하지 않은가? 라는 생각이다. 함수의 parameter만 해도 인터페이스의 역할을 한다. 내부적으로 개발 경험에서 혼선을 줄여주는 규격! 이라고 생각하겠다. 

 

ps. 좀더 찾아보니 abstract class를 implements하는 상황에서 interface라고 부른단다. 그런데 용어정리는그거나름대로 의미가 있지만 난 개념자체에 관심이 있는것. 결국 개발 환경에서 인터페이스를 정의한 이유가 중요한거 아니겠는가.

나의 코드에 필수적인 요소를 규격화 하는 작업은 꽤나 거부감없이 적용된다.

 

/**

오픈소스 프로젝트에서 내 pr에 어떤분이 남겨주신 리뷰가 계기가 되어 생각을 고쳐먹었다! 기본부터 제대로 이해해보기로!  근데 이해하면서 개발한다는게 왕재밌고 유익함.

 

To be continued.