Autumn SALE
반복자

자바로 작성된 반복자

반복자는 복잡한 데이터 구조의 내부 세부 정보를 노출하지 않고 해당 구조를 차례대로 순회할 수 있도록 하는 행동 디자인 패턴입니다.

반복자 덕분에 클라이언트들은 단일 반복기 인터페이스를 사용하여 유사한 방식으로 다른 컬렉션들의 요소들을 탐색할 수 있습니다.

복잡도:

인기도:

사용 예시들: 이 패턴은 자바 코드에 자주 사용됩니다. 많은 프레임워크들과 라이브러리들은 이 패턴을 컬렉션을 탐색하는 표준 방법을 제공하기 위해 사용합니다.

다음은 코어 자바 라이브러리로부터 가져온 몇 가지 예시들입니다:

식별법: 반복자는 그의 탐색 메서드들​(예: next, previous 등)​로 쉽게 인식할 수 있습니다. 또 반복자를 사용하는 클라이언트 코드는 반복자가 순회하는 컬렉션을 직접 접근하지 못할 수도 있습니다.

소셜 네트워크 프로필을 순회하기

이 예시는 반복자 패턴을 사용하여 클라이언트 코드에 아무런 통신 내용을 노출하지 않은 상태로 원격 소셜 네트워크 컬렉션의 소셜 프로필들을 순회하는 방법을 다룹니다.

iterators

iterators/ProfileIterator.java: 프로필 인터페이스의 정의

package refactoring_guru.iterator.example.iterators; import refactoring_guru.iterator.example.profile.Profile; public interface ProfileIterator { boolean hasNext(); Profile getNext(); void reset(); } 

iterators/FacebookIterator.java: 페이스북 프로필들에 대한 순회의 구현

package refactoring_guru.iterator.example.iterators; import refactoring_guru.iterator.example.profile.Profile; import refactoring_guru.iterator.example.social_networks.Facebook; import java.util.ArrayList; import java.util.List; public class FacebookIterator implements ProfileIterator { private Facebook facebook; private String type; private String email; private int currentPosition = 0; private List<String> emails = new ArrayList<>(); private List<Profile> profiles = new ArrayList<>(); public FacebookIterator(Facebook facebook, String type, String email) { this.facebook = facebook; this.type = type; this.email = email; } private void lazyLoad() { if (emails.size() == 0) { List<String> profiles = facebook.requestProfileFriendsFromFacebook(this.email, this.type); for (String profile : profiles) { this.emails.add(profile); this.profiles.add(null); } } } @Override public boolean hasNext() { lazyLoad(); return currentPosition < emails.size(); } @Override public Profile getNext() { if (!hasNext()) { return null; } String friendEmail = emails.get(currentPosition); Profile friendProfile = profiles.get(currentPosition); if (friendProfile == null) { friendProfile = facebook.requestProfileFromFacebook(friendEmail); profiles.set(currentPosition, friendProfile); } currentPosition++; return friendProfile; } @Override public void reset() { currentPosition = 0; } } 

iterators/LinkedInIterator.java: 링크드인 프로필들에 대한 순회의 구현

package refactoring_guru.iterator.example.iterators; import refactoring_guru.iterator.example.profile.Profile; import refactoring_guru.iterator.example.social_networks.LinkedIn; import java.util.ArrayList; import java.util.List; public class LinkedInIterator implements ProfileIterator { private LinkedIn linkedIn; private String type; private String email; private int currentPosition = 0; private List<String> emails = new ArrayList<>(); private List<Profile> contacts = new ArrayList<>(); public LinkedInIterator(LinkedIn linkedIn, String type, String email) { this.linkedIn = linkedIn; this.type = type; this.email = email; } private void lazyLoad() { if (emails.size() == 0) { List<String> profiles = linkedIn.requestRelatedContactsFromLinkedInAPI(this.email, this.type); for (String profile : profiles) { this.emails.add(profile); this.contacts.add(null); } } } @Override public boolean hasNext() { lazyLoad(); return currentPosition < emails.size(); } @Override public Profile getNext() { if (!hasNext()) { return null; } String friendEmail = emails.get(currentPosition); Profile friendContact = contacts.get(currentPosition); if (friendContact == null) { friendContact = linkedIn.requestContactInfoFromLinkedInAPI(friendEmail); contacts.set(currentPosition, friendContact); } currentPosition++; return friendContact; } @Override public void reset() { currentPosition = 0; } } 

social_networks

social_networks/SocialNetwork.java: 공통 소셜 네트워크 인터페이스의 정의

package refactoring_guru.iterator.example.social_networks; import refactoring_guru.iterator.example.iterators.ProfileIterator; public interface SocialNetwork { ProfileIterator createFriendsIterator(String profileEmail); ProfileIterator createCoworkersIterator(String profileEmail); } 

social_networks/Facebook.java: 페이스북

package refactoring_guru.iterator.example.social_networks; import refactoring_guru.iterator.example.iterators.FacebookIterator; import refactoring_guru.iterator.example.iterators.ProfileIterator; import refactoring_guru.iterator.example.profile.Profile; import java.util.ArrayList; import java.util.List; public class Facebook implements SocialNetwork { private List<Profile> profiles; public Facebook(List<Profile> cache) { if (cache != null) { this.profiles = cache; } else { this.profiles = new ArrayList<>(); } } public Profile requestProfileFromFacebook(String profileEmail) { // Here would be a POST request to one of the Facebook API endpoints. // Instead, we emulates long network connection, which you would expect // in the real life... simulateNetworkLatency(); System.out.println("Facebook: Loading profile '" + profileEmail + "' over the network..."); // ...and return test data. return findProfile(profileEmail); } public List<String> requestProfileFriendsFromFacebook(String profileEmail, String contactType) { // Here would be a POST request to one of the Facebook API endpoints. // Instead, we emulates long network connection, which you would expect // in the real life... simulateNetworkLatency(); System.out.println("Facebook: Loading '" + contactType + "' list of '" + profileEmail + "' over the network..."); // ...and return test data. Profile profile = findProfile(profileEmail); if (profile != null) { return profile.getContacts(contactType); } return null; } private Profile findProfile(String profileEmail) { for (Profile profile : profiles) { if (profile.getEmail().equals(profileEmail)) { return profile; } } return null; } private void simulateNetworkLatency() { try { Thread.sleep(2500); } catch (InterruptedException ex) { ex.printStackTrace(); } } @Override public ProfileIterator createFriendsIterator(String profileEmail) { return new FacebookIterator(this, "friends", profileEmail); } @Override public ProfileIterator createCoworkersIterator(String profileEmail) { return new FacebookIterator(this, "coworkers", profileEmail); } } 

social_networks/LinkedIn.java: 링크드인

package refactoring_guru.iterator.example.social_networks; import refactoring_guru.iterator.example.iterators.LinkedInIterator; import refactoring_guru.iterator.example.iterators.ProfileIterator; import refactoring_guru.iterator.example.profile.Profile; import java.util.ArrayList; import java.util.List; public class LinkedIn implements SocialNetwork { private List<Profile> contacts; public LinkedIn(List<Profile> cache) { if (cache != null) { this.contacts = cache; } else { this.contacts = new ArrayList<>(); } } public Profile requestContactInfoFromLinkedInAPI(String profileEmail) { // Here would be a POST request to one of the LinkedIn API endpoints. // Instead, we emulates long network connection, which you would expect // in the real life... simulateNetworkLatency(); System.out.println("LinkedIn: Loading profile '" + profileEmail + "' over the network..."); // ...and return test data. return findContact(profileEmail); } public List<String> requestRelatedContactsFromLinkedInAPI(String profileEmail, String contactType) { // Here would be a POST request to one of the LinkedIn API endpoints. // Instead, we emulates long network connection, which you would expect // in the real life. simulateNetworkLatency(); System.out.println("LinkedIn: Loading '" + contactType + "' list of '" + profileEmail + "' over the network..."); // ...and return test data. Profile profile = findContact(profileEmail); if (profile != null) { return profile.getContacts(contactType); } return null; } private Profile findContact(String profileEmail) { for (Profile profile : contacts) { if (profile.getEmail().equals(profileEmail)) { return profile; } } return null; } private void simulateNetworkLatency() { try { Thread.sleep(2500); } catch (InterruptedException ex) { ex.printStackTrace(); } } @Override public ProfileIterator createFriendsIterator(String profileEmail) { return new LinkedInIterator(this, "friends", profileEmail); } @Override public ProfileIterator createCoworkersIterator(String profileEmail) { return new LinkedInIterator(this, "coworkers", profileEmail); } } 

profile

profile/Profile.java: 소셜 프로필

package refactoring_guru.iterator.example.profile; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; public class Profile { private String name; private String email; private Map<String, List<String>> contacts = new HashMap<>(); public Profile(String email, String name, String... contacts) { this.email = email; this.name = name; // Parse contact list from a set of "friend:email@gmail.com" pairs. for (String contact : contacts) { String[] parts = contact.split(":"); String contactType = "friend", contactEmail; if (parts.length == 1) { contactEmail = parts[0]; } else { contactType = parts[0]; contactEmail = parts[1]; } if (!this.contacts.containsKey(contactType)) { this.contacts.put(contactType, new ArrayList<>()); } this.contacts.get(contactType).add(contactEmail); } } public String getEmail() { return email; } public String getName() { return name; } public List<String> getContacts(String contactType) { if (!this.contacts.containsKey(contactType)) { this.contacts.put(contactType, new ArrayList<>()); } return contacts.get(contactType); } } 

spammer

spammer/SocialSpammer.java: 메시지 전송 앱

package refactoring_guru.iterator.example.spammer; import refactoring_guru.iterator.example.iterators.ProfileIterator; import refactoring_guru.iterator.example.profile.Profile; import refactoring_guru.iterator.example.social_networks.SocialNetwork; public class SocialSpammer { public SocialNetwork network; public ProfileIterator iterator; public SocialSpammer(SocialNetwork network) { this.network = network; } public void sendSpamToFriends(String profileEmail, String message) { System.out.println("\nIterating over friends...\n"); iterator = network.createFriendsIterator(profileEmail); while (iterator.hasNext()) { Profile profile = iterator.getNext(); sendMessage(profile.getEmail(), message); } } public void sendSpamToCoworkers(String profileEmail, String message) { System.out.println("\nIterating over coworkers...\n"); iterator = network.createCoworkersIterator(profileEmail); while (iterator.hasNext()) { Profile profile = iterator.getNext(); sendMessage(profile.getEmail(), message); } } public void sendMessage(String email, String message) { System.out.println("Sent message to: '" + email + "'. Message body: '" + message + "'"); } } 

Demo.java: 클라이언트 코드

package refactoring_guru.iterator.example; import refactoring_guru.iterator.example.profile.Profile; import refactoring_guru.iterator.example.social_networks.Facebook; import refactoring_guru.iterator.example.social_networks.LinkedIn; import refactoring_guru.iterator.example.social_networks.SocialNetwork; import refactoring_guru.iterator.example.spammer.SocialSpammer; import java.util.ArrayList; import java.util.List; import java.util.Scanner; /** * Demo class. Everything comes together here. */ public class Demo { public static Scanner scanner = new Scanner(System.in); public static void main(String[] args) { System.out.println("Please specify social network to target spam tool (default:Facebook):"); System.out.println("1. Facebook"); System.out.println("2. LinkedIn"); String choice = scanner.nextLine(); SocialNetwork network; if (choice.equals("2")) { network = new LinkedIn(createTestProfiles()); } else { network = new Facebook(createTestProfiles()); } SocialSpammer spammer = new SocialSpammer(network); spammer.sendSpamToFriends("anna.smith@bing.com", "Hey! This is Anna's friend Josh. Can you do me a favor and like this post [link]?"); spammer.sendSpamToCoworkers("anna.smith@bing.com", "Hey! This is Anna's boss Jason. Anna told me you would be interested in [link]."); } public static List<Profile> createTestProfiles() { List<Profile> data = new ArrayList<Profile>(); data.add(new Profile("anna.smith@bing.com", "Anna Smith", "friends:mad_max@ya.com", "friends:catwoman@yahoo.com", "coworkers:sam@amazon.com")); data.add(new Profile("mad_max@ya.com", "Maximilian", "friends:anna.smith@bing.com", "coworkers:sam@amazon.com")); data.add(new Profile("bill@microsoft.eu", "Billie", "coworkers:avanger@ukr.net")); data.add(new Profile("avanger@ukr.net", "John Day", "coworkers:bill@microsoft.eu")); data.add(new Profile("sam@amazon.com", "Sam Kitting", "coworkers:anna.smith@bing.com", "coworkers:mad_max@ya.com", "friends:catwoman@yahoo.com")); data.add(new Profile("catwoman@yahoo.com", "Liza", "friends:anna.smith@bing.com", "friends:sam@amazon.com")); return data; } } 

OutputDemo.txt: 실행 결과

Please specify social network to target spam tool (default:Facebook): 1. Facebook 2. LinkedIn > 1 Iterating over friends... Facebook: Loading 'friends' list of 'anna.smith@bing.com' over the network... Facebook: Loading profile 'mad_max@ya.com' over the network... Sent message to: 'mad_max@ya.com'. Message body: 'Hey! This is Anna's friend Josh. Can you do me a favor and like this post [link]?' Facebook: Loading profile 'catwoman@yahoo.com' over the network... Sent message to: 'catwoman@yahoo.com'. Message body: 'Hey! This is Anna's friend Josh. Can you do me a favor and like this post [link]?' Iterating over coworkers... Facebook: Loading 'coworkers' list of 'anna.smith@bing.com' over the network... Facebook: Loading profile 'sam@amazon.com' over the network... Sent message to: 'sam@amazon.com'. Message body: 'Hey! This is Anna's boss Jason. Anna told me you would be interested in [link].' 

다른 언어로 작성된 반복자

C#으로 작성된 반복자 C++로 작성된 반복자 Go로 작성된 반복자 PHP로 작성된 반복자 파이썬으로 작성된 반복자 루비로 작성된 반복자 러스트로 작성된 반복자 스위프트로 작성된 반복자 타입스크립트로 작성된 반복자