diff --git "a/\352\265\254\354\241\260/6\354\243\274\354\260\250-\355\224\214\353\235\274\354\235\264\354\233\250\354\235\264\355\212\270/summary/code.md" "b/\352\265\254\354\241\260/6\354\243\274\354\260\250-\355\224\214\353\235\274\354\235\264\354\233\250\354\235\264\355\212\270/summary/code.md" new file mode 100644 index 0000000..27ba4bf --- /dev/null +++ "b/\352\265\254\354\241\260/6\354\243\274\354\260\250-\355\224\214\353\235\274\354\235\264\354\233\250\354\235\264\355\212\270/summary/code.md" @@ -0,0 +1,104 @@ +## 예제 코드 + +### 요구사항 +1. 사람인에 근무하고 있는 사람들의 정보를 볼 수 있는 시스템을 만들고 싶어요. +2. 근무자들은 한 조직(팀)에 속해 있으니 팀의 정보도 포함해야 해요. + +이를 위해 사람인의 근무자들의 정보를 DB나 api를 통하여 데이터를 불러와 각각 Member라는 객체로 만들어 서비스를 개발할 수 있을 것이다. + +여기서 우리는 Member나는 객체를 만드는 과정에 집중해서 살펴 볼 것이다. + +### 패턴 적용 전 코드 +```java +@AllArgsConstructor +public class Member { + private String name; //이름 + private LocalDate birthDay; //생일 + private String description; //기타 설명 + private String position; //직급 + private String organizationName; //조직이름 + private String teamName; //팀이름 + private String partName; //파트이름 +} + +public class Client { + public static void main(String[] args) { + Member member1 = new Member("고길동", LocalDate.of(1980,12,7),"종로로 갈까요?", + "파트장","IT연구소","사람인개발팀","D1"); + Member member2 = new Member("고둘리", LocalDate.of(1995,4,8),"호잇!", + "팀원","IT연구소","사람인개발팀","D1"); + Member member3 = new Member("또치", LocalDate.of(1988,2,7),"난 세상에서 가장 우아하고, 잘난 귀족 타조야", + "파트장","IT연구소","사람인개발팀","D2"); + Member member4 = new Member("도우너", LocalDate.of(1992,8,17),"안녕하세요!!", + "팀원","IT연구소","사람인개발팀","D2"); + Member member5 = new Member("마이클", LocalDate.of(1990,3,27),"안녕하세요!!", + "팀원","IT연구소","사람인개발팀","D2"); + } +} +``` +예시에서는 팀원이 5명밖에 안되긴 하지만 5명의 예시만 봐도 팀정보와 같이 중복되며 자주 변하지 않는 데이터가 보일 것이다. + +이런 부분들을 분류하고 플라이웨이트 패턴을 적용해서 메모리를 절약해보자. + +### 적용 후 코드 +```java +@AllArgsConstructor +public class Member { + private String name; + private LocalDate birthDay; + private String description; + private String position; + private Team team; //자주 변하지 않을 팀 정보를 따로 객체로 분리 +} + +//팀 정보 객체 +//Flyweight +@AllArgsConstructor +public class Team { + private String organizationName; + private String teamName; + private String partName; +} + +//FlyWeight Factory +public class TeamFactory { + private final Map cache = new HashMap<>(); //캐싱하기 위한 Map + private final Pattern teamPattern = Pattern.compile("([a-zA-Z0-9가-힣 ]*):([a-zA-Z0-9가-힣 ]*):([a-zA-Z0-9가-힣 ]*)"); //team조회를 위한 입력 표현식 (조직이름:팀이름:파트이름) + + public Team getTeam(String team) { + Matcher teamMatcher = teamPattern.matcher(team); + + //정의한 regxr과 다르다면 error + if(!teamMatcher.matches()){ + throw new IllegalArgumentException(); + } + + if (cache.containsKey(team)) { + return cache.get(team); //캐싱되어있다면 바로 반환 + } else { + Team newTeam = new Team(teamMatcher.group(1),teamMatcher.group(2),teamMatcher.group(3)); //새로운 팀 생성 + cache.put(team, newTeam); //캐싱 + return newTeam; + } + } +} + +//Client +//FlyWeight를 사용 +public class Client { + public static void main(String[] args) { + TeamFactory teamFactory = new TeamFactory(); + + Member member1 = new Member("고길동", LocalDate.of(1980,12,7),"종로로 갈까요?", + "파트장",teamFactory.getTeam("IT연구소:사람인개발팀:D1")); + Member member2 = new Member("고둘리", LocalDate.of(1995,4,8),"호잇!", + "팀원",teamFactory.getTeam("IT연구소:사람인개발팀:D1")); + Member member3 = new Member("또치", LocalDate.of(1988,2,7),"난 세상에서 가장 우아하고, 잘난 귀족 타조야", + "파트장",teamFactory.getTeam("IT연구소:사람인개발팀:D2")); + Member member4 = new Member("도우너", LocalDate.of(1992,8,17),"안녕하세요!!", + "팀원",teamFactory.getTeam("IT연구소:사람인개발팀:D2")); + Member member5 = new Member("마이클", LocalDate.of(1990,3,27),"안녕하세요!!", + "팀원",teamFactory.getTeam("IT연구소:사람인개발팀:D2")); + } +} +``` \ No newline at end of file diff --git "a/\352\265\254\354\241\260/6\354\243\274\354\260\250-\355\224\214\353\235\274\354\235\264\354\233\250\354\235\264\355\212\270/summary/\355\224\214\353\235\274\354\235\264\354\233\250\354\235\264\355\212\270 \355\214\250\355\204\264.md" "b/\352\265\254\354\241\260/6\354\243\274\354\260\250-\355\224\214\353\235\274\354\235\264\354\233\250\354\235\264\355\212\270/summary/\355\224\214\353\235\274\354\235\264\354\233\250\354\235\264\355\212\270 \355\214\250\355\204\264.md" new file mode 100644 index 0000000..c525479 --- /dev/null +++ "b/\352\265\254\354\241\260/6\354\243\274\354\260\250-\355\224\214\353\235\274\354\235\264\354\233\250\354\235\264\355\212\270/summary/\355\224\214\353\235\274\354\235\264\354\233\250\354\235\264\355\212\270 \355\214\250\355\204\264.md" @@ -0,0 +1,154 @@ +# 플라이웨이트 패턴 + +> 객체를 가볍게 만들어 메모리 사용을 줄이는 패턴 + +![](https://refactoring.guru/images/patterns/diagrams/flyweight/structure.png) + +`FlyweightFactory` : 공통으로 사용하는 Flyweight를 생성하는 팩토리 클래스 + +`Flyweight`: 공유에 사용하는 클래스 + +**인스턴스를 최초만 생성해서 그 이후부터는 재사용** 자주 변하는 속성, 그리고 자주 변하지 않는 속성을 분리해서, 메모리 사용을 줄이는 패턴이다. + +## 플라이웨이트는 언제 사용되는가? + +- 공통적인 인스턴스를 많이 생성하는 로직이 포함되어있는 경우 + +- 자주 변하지 않는 속성을 재사용할 수 있는 경우 + +## 플라이웨이트 패턴 예제 코드 + +### 요구사항 + +1. 사람인에 근무하고 있는 사람들의 정보를 볼 수 있는 시스템을 만들고 싶어요. +2. 근무자들은 한 조직(팀)에 속해 있으니 팀의 정보도 포함해야 해요. + +이를 위해 사람인의 근무자들의 정보를 DB나 api를 통하여 데이터를 불러와 각각 Member라는 객체로 만들어 서비스를 개발할 수 있을 것이다. + +여기서 우리는 Member나는 객체를 만드는 과정에 집중해서 살펴 볼 것이다. + +### 패턴 적용 전 코드 + +```java +@AllArgsConstructor +public class Member { + private String name; //이름 + private LocalDate birthDay; //생일 + private String description; //기타 설명 + private String position; //직급 + private String organizationName; //조직이름 + private String teamName; //팀이름 + private String partName; //파트이름 +} + +public class Client { + public static void main(String[] args) { + Member member1 = new Member("고길동", LocalDate.of(1980,12,7),"종로로 갈까요?", + "파트장","IT연구소","사람인개발팀","D1"); + Member member2 = new Member("고둘리", LocalDate.of(1995,4,8),"호잇!", + "팀원","IT연구소","사람인개발팀","D1"); + Member member3 = new Member("또치", LocalDate.of(1988,2,7),"난 세상에서 가장 우아하고, 잘난 귀족 타조야", + "파트장","IT연구소","사람인개발팀","D2"); + Member member4 = new Member("도우너", LocalDate.of(1992,8,17),"안녕하세요!!", + "팀원","IT연구소","사람인개발팀","D2"); + Member member5 = new Member("마이클", LocalDate.of(1990,3,27),"안녕하세요!!", + "팀원","IT연구소","사람인개발팀","D2"); + } +} +``` + +예시에서는 팀원이 5명밖에 안되긴 하지만 5명의 예시만 봐도 팀정보와 같이 중복되며 자주 변하지 않는 데이터가 보일 것이다. + +이런 부분들을 분류하고 플라이웨이트 패턴을 적용해서 메모리를 절약해보자. + +### 적용 후 코드 + +```java +@AllArgsConstructor +public class Member { + private String name; + private LocalDate birthDay; + private String description; + private String position; + private Team team; //자주 변하지 않을 팀 정보를 따로 객체로 분리 +} + +//팀 정보 객체 +//Flyweight +@AllArgsConstructor +public class Team { + private String organizationName; + private String teamName; + private String partName; +} + +//FlyWeight Factory +public class TeamFactory { + private final Map cache = new HashMap<>(); //캐싱하기 위한 Map + private final Pattern teamPattern = Pattern.compile("([a-zA-Z0-9가-힣 ]*):([a-zA-Z0-9가-힣 ]*):([a-zA-Z0-9가-힣 ]*)"); //team조회를 위한 입력 표현식 (조직이름:팀이름:파트이름) + + public Team getTeam(String team) { + Matcher teamMatcher = teamPattern.matcher(team); + + //정의한 regxr과 다르다면 error + if(!teamMatcher.matches()){ + throw new IllegalArgumentException(); + } + + if (cache.containsKey(team)) { + return cache.get(team); //캐싱되어있다면 바로 반환 + } else { + Team newTeam = new Team(teamMatcher.group(1),teamMatcher.group(2),teamMatcher.group(3)); //새로운 팀 생성 + cache.put(team, newTeam); //캐싱 + return newTeam; + } + } +} + +//Client +//FlyWeight를 사용 +public class Client { + public static void main(String[] args) { + TeamFactory teamFactory = new TeamFactory(); + + Member member1 = new Member("고길동", LocalDate.of(1980,12,7),"종로로 갈까요?", + "파트장",teamFactory.getTeam("IT연구소:사람인개발팀:D1")); + Member member2 = new Member("고둘리", LocalDate.of(1995,4,8),"호잇!", + "팀원",teamFactory.getTeam("IT연구소:사람인개발팀:D1")); + Member member3 = new Member("또치", LocalDate.of(1988,2,7),"난 세상에서 가장 우아하고, 잘난 귀족 타조야", + "파트장",teamFactory.getTeam("IT연구소:사람인개발팀:D2")); + Member member4 = new Member("도우너", LocalDate.of(1992,8,17),"안녕하세요!!", + "팀원",teamFactory.getTeam("IT연구소:사람인개발팀:D2")); + Member member5 = new Member("마이클", LocalDate.of(1990,3,27),"안녕하세요!!", + "팀원",teamFactory.getTeam("IT연구소:사람인개발팀:D2")); + } +} +``` + +## 패턴의 장/단점 + +장점: + +- 프로그램에 비슷한 오브젝트가 엄청나게 많은 경우 램을 엄청 많이 줄일 수 있다. + + + +단점: + +- 누군가 Flyweight 메서드를 호출할 때마다 다시 데이터를 호출해서 캐시값이 변경되면 CPU 사이클 때문에, RAM 추가 소비 발생할 수 있다. + +- 코드가 꽤 많이 복잡해질 수 있음. 새로운 팀 맴버가 들어올 경우 이런 상태로 왜 구성되어있는지 파악하기가 어려울 수 있다. + +## 비슷한 패턴 + +- 컴포짓 패턴의 공유 리프 노드를 플라이웨이트로 구현하면 램절약이 가능해진다. + +- 플라이웨이트는 어떻게 작은 오브젝트가 꽤 많이 생성되는지를 보여준다면, 파사드는 서브시스템의 한 전체를 나타내는 한 객체가 만들어지는 방식을 보여준다. + +- 플라이웨이트를 개체의 모든 공유 상태를 하나의 Flyweight 객체로 줄일 수 있으면 싱글톤이랑 비슷하다. 하지만, 둘은 근본적인 차이가 존재한다. + + - 싱글톤 인스턴스는 오직 한개만 있지만, 플라이웨이트 클래스는 다른 변하지 않는 상태들과 함께 여러 인스턴스를 가질 수 있다. + + - 싱글톤 객체는 변할 수 있지만, 플라이 웨이트는 불변하다. + +