기존 시각화 소스코드의 문제점 - 관심사의 분리 X, 필드 값 외부 주입 필요
자바에서는 객체지향의 원칙을 지키며 프로그래밍 하는 것이 아주 중요합니다. 기존의 소스코드는 관심사의 분리가 되어 있지 않고 하나의 public 클래스에 내부 클래스로 모든 기능이 구현되어 있었습니다.
그리고 가장 심각한 문제는 태그의 좌표가 하드코딩 되어 있다는 것입니다. 이를 외부에서 주입해서 소스코드를 수정하지 않고도 앵커의 좌표값을 세팅할 수 있어야 합니다.
이 프로그램에서 태그의 좌표는 SWING을 사용하여 화면에 앵커의 위치를 그릴 때 1번, Trilateraion할 때 1번, 총 2번에 걸쳐서 태그의 좌표가 사용됩니다. 이 두 부분이 모두 하드코딩 되어 있었고, Anchor의 클래스가 따로 분리 되어 있지 않아서 getter로 참조할수도 없었습니다.
Trilateration을 하는 클래스에서 앵커의 좌표를 얻기 위해서 CoordinatePanel클래스의 멤버 변수로 등록되어 있는 앵커의 좌표를 참조하게 된다면 이는 객체지향의 관점에서 옳지 않습니다. CoordinatePanel 클래스에서는 화면에 그리는 역할만을 수행해야 하는데 앵커의 좌표를 제공하기 위해서 getter 메소드를 추가하면 안됩니다
문제점 해결 - 관심사 분리, Reflection API 사용하여 필드 값 주입
각 역할과 구현을 분리하기 위해서 아래와 같이 서로 다른 역할을 가지고 있는 클래스들을 모두 분리했습니다.
앵커 클래스에서는 3개의 앵커의 x, y좌표를 멤버 변수로 가지고 있습니다.
Spring에서도 의존관계 주입을 위해서 Reflection API를 사용합니다. Reflection API를 사용하면 접근지시제어자가 private인 클래스의 객체를 생성할 수도 있고, 메서드를 호출하고 필드에 값을 주입할 수도 있습니다.
Config클래스의 생성자에 앵커의 값을 주입하는 소스코드를 작성함으로써, 인스턴스가 생성됨과 동시에 값 주입 로직이 실행되도록 구현했습니다.
- 클래스의 class 프로퍼티를 통해서 앵커 클래스의 객체를 획득합니다.
- getDeclaredFiled() 메서드를 통해서 앵커 클래스에서 정의 된 모든 멤버 변수를 Field 타입의 배열로 리턴합니다.
- 앵커 클래스의 멤버 변수는 모두 private으로 선언되어 있기 때문에, setAccessible() 메소드를 통해서 private에 접근할 수 있도록 합니다.
그리고 set() 메소드를 통해서 값을 설정할 수 있습니다.
이로써, 앵커 클래스를 수정하지 않고도 외부에서 앵커의 x, y좌표를 수정할 수 있게 되었습니다.
또 다른 문제점 발생 - 외부에서 주입한 값 적용 안됨
config에서 앵커의 좌표값을 주입했는데도, 프로그램을 실행시키면 앵커의 좌표값이 주입된 값으로 적용되지 않는 문제점이 발생했습니다.
main 메서드의 실행로직은 TagCoordinate의 인스턴스를 생성하고, StartServer 메소드를 실행합니다.
TagCoordinate의 생성자에서는 1. config의 생성자를 호출하고 2.CoordintaePanel의 생성자를 호출합니다.
config의 기본 생성자에서 앵커 좌표값 주입이 실행되고,
CoordinatePanel 의 생성자에서는 화면에 흰 바탕을 그리는 로직만이 수행됩니다.
이후에는 아래와 같이 startServer 메소드가 실행됩니다.
startServer 메소드에서는 UDP 소켓 통신으로 게이트웨이로부터 각 앵커와 태그사이의 거리 값을 송신 한 후 파싱합니다.
그리고 Trilateraion 클래스의 객체를 호출해서 삼변측량법을 수행합니다.
삼변측량법을 수행할 때, 앵커의 객체를 생성해서 getter로 앵커의 좌표 값을 가져와야 합니다.
config 클래스에서 좌표 값을 주입한 앵커 클래스의 인스턴스와, Trilatertaion 클래스에서 좌표 값 참조를 위해 생성한 앵커 클래스의 인스턴스는 다른 인스턴스입니다.
자바는 new 키워드를 통해서 객체의 인스턴스를 생성할때 힙 메모리에 인스턴스가 생성됩니다.
위에서 언급했듯이, 이 프로그램에서는 앵커의 좌표가 총 2번, 삼변측량법을 실시할때, 그리고 화면에 출력할때 사용됩니다.
그 때마다 앵커 클래스의 인스턴스를 생성하면 각각의 다른 인스턴스가 힙 메모리에 존재하게 되고, config 클래스에서 좌표값을 주입했던 인스턴스와는 다른 별개의 인스턴스를 사용하는 것입니다.
그래서 외부에서 앵커의 좌표값을 주입했음에도 불구하고 화면에 출력될때는 적용되지 않았던 것입니다.
문제 해결 - 싱글톤 패턴 적용
Spring에서도 특정 역할을 하는 클래스를 bean으로 등록을 하게 되는데, 사용자가 똑같은 요청을 수백만건을 했다고 가정했을 때 요청할 때 마다 bean에 등록된 클래스의 인스턴스를 생성해서 반환할 수가 없습니다.
그렇기 때문에 Spring은 이러한 bean을 싱글톤 패턴으로 관리한다는 것을 배웠던 기억이 떠올랐습니다.
2023.05.17 - [자바 OOP] - 자바 Singleton Pattern(싱글톤 패턴)이란?
자바 Singleton Pattern(싱글톤 패턴)이란?
싱글톤 패턴이란 Gang of Four 디자인패턴 중 생성패턴 중의 한 종류입니다. 프로그램에서 인스턴스가 단 하나만 생성되어야 하는 경우 사용되는 디자인패턴입니다. 자바에서 싱글톤 패턴을 사용
iamdongmin.tistory.com
이 프로그램에서도 앵커의 좌표값을 사용하기 위해서 앵커 클래스의 인스턴스를 여러번 생성해야 하는데, 외부에서 주입한 좌표값이 유지되기 위해서는 단 하나의 인스턴스만 공유해서 사용해야 합니다.
- private static으로 선언된 Anchor를 타입으로 사용하는 instance객체에 Anchor의 인스턴스를 생성해서 넣습니다.
- 앵커 클래스의 생성자를 private으로 막아서 외부에서 호출하는 것을 막습니다.
- static으로 선언했기 때문에 프로그램이 실행되자마자 Anchor의 인스턴스는 바로 생성됩니다.
- 이후에 다른 클래스에서는 getInstance 메소드를 사용해서 getter에 접근할 수 있습니다.
아래와 같이 Trilateraion 클래스와, CoordinatePanel 클래스에서도 모두 동일한 인스턴스의 값을 참조하는 모습을 볼 수 있습니다.
이로써 문제가 해결되었습니다.
'위치인식 연구' 카테고리의 다른 글
[실시간 위치인식 시스템] 기존 시스템의 문제점 파악 및 개선, 시각화 소스코드 구현 (0) | 2023.08.11 |
---|---|
Channel Impulse Response란? (0) | 2023.05.14 |