λͺ©μ°¨
- μλ‘
- instanceof λ?
- μ½λμμ instanceof λ₯Ό λ껴보μ
- Generic μ μ΄μ©νμ¬ μ°μνκ² μ κ±°νκΈ°
- κ·ΈλΌμλ μ‘΄μ¬νλ λ¬Έμ μ
- νμ§λ§?
μλ‘
μλ°μμ λ€νμ±μ μ΄μ©ν κ°μ²΄μ§ν₯μ νλ‘κ·Έλλ°μ νλ€λ³΄λ©΄ μ’ μ’ νΉμ κ°μ²΄κ° μ§μ λ μ νμ μΈμ€ν΄μ€μΈμ§ νμΈν΄μΌ νλ κ²½μ°κ° μλ€.
κ·Έ κ²½μ° μ°λ¦¬λ μ¬λ¬κ°μ§ μ νμ§κ° μμ§λ§, μ€λμ instanceof μ λν΄ μ§μ€νκ³ μ΄μΌκΈ°ν΄λ³΄λ € νλ€.
λ€νμ±μ μ΄μ©ν νλ‘κ·Έλλ°μ νλ€ λ³΄λ©΄ νΉμ νμΌλ‘ λ³ννκΈ° μν΄ λͺκ°μ§ μμ μ ν΄μΌ νλλ°, κ·Έμ€ λνμ μΈ κ²μ΄ λ°λ‘ instanceof μ°μ°μμ΄λ€.
instanceof λ?
μμ λ§νλ― Java μμλ μ΄λ€ κ°μ²΄μ νΉμ type μ λν΄μ λμΌν type μΈμ§ νμΈν μ μλ μ°μ°μ instanceof μ°μ°μλ₯Ό ν΅ν΄μ μννκ³ μλ€.
μλ₯Ό λ€μ΄μ λ€μκ³Ό κ°μ μν©μμμ μ½λλ₯Ό 보μ
User λ μ΄ 3κ°μ§μ νν(Guest, Member, Admin)κ° μ‘΄μ¬νλ€.
public interface User {
// User μΈν°νμ΄μ€
}
// κ²μ€νΈ
public class Guest implements User {}
// λ©€λ², μΌλ° μ μ
public class Member implements User {}
// κ΄λ¦¬μ
public class Admin implements User {}
public class Testing {
@Test
void test() {
User admin = new Admin();
boolean actual = admin instanceof Admin;
assertThat(actual).isTrue();
}
}
λΉμ°νκ²λ μμ μ½λλ μ±κ³΅νκ² λλ€.
νμ§λ§ μΌκ°μμλ μ΄λ¬ν instanceof μ μ¬μ©μ λμ λμλΌκ³ ν΄μνκΈ°λ νλ©° Anti-Pattern μ΄λΌλ μ견λ μ‘΄μ¬νλ€.
“instanceof”, Why And How To Avoid It In Code article
μ μ΄κ²μ΄ νΌν΄μΌν λμμΈμ§ μ½λλ¨μΌλ‘ ν λ² μμ보μ
μ½λμμ instanceof λ₯Ό λ껴보μ
μ½λμμ instanceof λ₯Ό λ껴보μ. μ μ΄λ₯Ό Anti-Pattern μ΄λΌκ³ νκ³ λμ λμλΌκ³ νλμ§.
μ°μ λ¬Έμ μν©μ μ΄λ¬νλ€.
μ¬μ©μμ μ νμ λ°λΌ ν μ μλ νλμ λ²μκ° λ¬λΌμ§λλ°, μ΄λ₯Ό νμΈν μ μλ μ΄λ ν κΈ°λ₯μ λ§λ€μ΄λ³΄λ € νλ€.
μμ κΈ°λ₯μ ꡬννλ€λ©΄ μλμ κ°μ΄ μΈλΆ λ΄μ© λ° νΉμ§κ³Ό μ μ½μ μ 리ν μ μμ κ²μ΄λ€.
μ¬μ©μ
- μ¬μ©μλ 3κ°μ§μ μ νκ³Ό κ°κ°μ νμκ° μ‘΄μ¬νλ€.
- Guest : λ°©λ¬Έμ
- κ°λ₯ν νμ : κΈ μ½κΈ°
- Member : νμ
- κ°λ₯ν νμ : κΈ μ½κΈ°, κΈ μ°κΈ°
- Admin : κ΄λ¦¬μ
- κ°λ₯ν νμ : κΈ μ½κΈ°, κΈ μ°κΈ°, κΈ μμ
- Guest : λ°©λ¬Έμ
Actuator
- Actuator μ μν΄μ κ°κ° μ¬μ©μμ νμλ₯Ό μΆλ ₯
- μ¬μ©μ μ νμ λ°λΌ Actuator λ₯Ό κ°κΈ° λ€λ₯΄κ² ꡬν
- GuestActuator : 1κ°μ νμλ₯Ό μΆλ ₯
- MemberActuator : 2κ°μ νμλ₯Ό μΆλ ₯
- AdminActuator : 3κ°μ νμλ₯Ό μΆλ ₯
- Composit ν¨ν΄μ μ΄μ©νμ¬ ActuatorContainer μμ Actuatorλ₯Ό ν©μ±νμ¬ μμ
- μ¬μ©μ μ νμ λ°λΌ Actuator λ₯Ό κ°κΈ° λ€λ₯΄κ² ꡬν
μ 체μ μ€κ³
μμ λ΄μ©λ€μ ν©μΉλ©΄ μλμ κ°μ μ€κ³κ° λμ€κ² λλ€.
κ·ΈλΌ μμ κ·Έλ¦Όμ ν λλ‘ μ€μ ꡬνμ ν΄λ³΄λλ‘ νμ
User ν¨ν€μ§
User ν¨ν€μ§λ User μλ‘ λ€λ₯Έ user μ ꡬν체λ€μ΄ μ‘΄μ¬νλ κ³³μ΄λ€.
3κ°μ§μ User Type μ λ΄λ³΄μ
// UserType Enum
public enum UserType {
GUEST, ADMIN, MEMBER
}
// User Interface
public interface User {
UserType getType();
void readArticle();
}
// Guest Class
public class Guest implements User {
@Override
public UserType getType() {
return UserType.GUEST;
}
@Override
public void readArticle() {
System.out.println("Guest λ Article μ μ½μ μ μμ΅λλ€.");
}
}
// Member Class
public class Member implements User {
@Override
public UserType getType() {
return UserType.MEMBER;
}
@Override
public void readArticle() {
System.out.println("Member μ Article μ μ½μ μ μμ΅λλ€.");
}
public void createArticle() {
System.out.println("Member μ Article μ μμ±ν μ μμ΅λλ€.");
}
}
// Admin Class
public class Admin implements User {
@Override
public UserType getType() {
return UserType.ADMIN;
}
@Override
public void readArticle() {
System.out.println("Admin μ Article μ μ½μ μ μμ΅λλ€.");
}
public void createArticle() {
System.out.println("Admin μ Article μ μμ±ν μ μμ΅λλ€.");
}
public void deleteArticle() {
System.out.println("Admin μ Article μ μμ ν μ μμ΅λλ€.");
}
}
μμ μ΄μΌκΈ°νλ λ°μ κ°μ΄ 3κ°μ§μ μλ‘ λ€λ₯Έ μ¬μ©μ μ νμ μλ‘ λ€λ₯Έ κΆνμ κ°μ§κ³ μκ³ , User λ₯Ό μμ±νλ ν΄λΌμ΄μΈνΈμμλ μ μ ν μν©μ μ μ ν User νμ ꡬν체λ€μ μμ±ν΄μ€μΌ νλ€.
μ΄μ User λ₯Ό μ¬μ©νλ μͺ½μ κ°λ³΄μ
Actuatorλ€
Actuator μμλ User λ₯Ό 맀κ°λ³μλ‘ λ°μμ User κ° ν μ μλ νλλ€μ μ·¨νλ€.
3κ°μ UserType μ΄ μ‘΄μ¬νλ―λ‘ 3κ°μ Actuator λ₯Ό λ§λ€μ΄λ³΄μ.
public interface UserActuator {
void describeActions(User user);
}
public class GuestActuator implements UserActuator {
@Override
public void describeActions(User user) {
if (!(user instanceof Guest)) {
throw new IllegalArgumentException("Guest κ° μλλλ€.");
}
user.readArticle();
}
}
public class MemberActuator implements UserActuator {
@Override
public void describeActions(User user) {
if (!(user instanceof Member)) {
throw new IllegalArgumentException("Member κ° μλλλ€.");
}
Member member = new Member();
member.readArticle();
member.createArticle();
}
}
public class AdminActuator implements UserActuator {
@Override
public void describeActions(User user) {
if (!(user instanceof Admin)) {
throw new IllegalArgumentException("Admin μ΄ μλλλ€.");
}
Admin admin = (Admin) user;
admin.readArticle();
admin.createArticle();
admin.deleteArticle();
}
}
- GuestActuator
- MemberActuator
- AdminActuator
μ΄ 3κ°μ§μ Actuator λ‘ User λ₯Ό 맀κ°λ³μλ‘ λ°μμ ν΄λΉ User κ°μ²΄κ° μ§μ§ Actuator κ° μνλ νμ μΈμ§ λ¨Όμ νμΈνλ μ½λκ° μ‘΄μ¬νλ€.
μ΄ κ³Όμ μμ μ½λμ λμκ° λκΈ° μμνλ€.
νΉμ Actuator μ μ₯μμλ μ κ³μν΄μ User κ° μ¬λ°λ₯Έμ§ νμΈν΄μΌ ν κΉ?
Actuatorλ μ μ΄μ Userλ₯Ό λ°μ λ νμ μ λ§λ User λ§ λ°μΌλ©΄ λμ§ μμκΉ?
μΌλ¨ λ¬Έμ μ μ΄λΌκ³ μκ°λλ λΆλΆμ μ°ΎμμΌλ λ§μ§λ§ λ¨μ ActuatorContainer λ₯Ό ꡬνν΄μ£Όμ.
public class ActuatorContainer implements UserActuator {
private final Map<UserType, UserActuator> map;
public ActuatorContainer() {
this.map = new HashMap<>();
map.put(UserType.GUEST, new GuestActuator());
map.put(UserType.MEMBER, new MemberActuator());
map.put(UserType.ADMIN, new AdminActuator());
}
@Override
public void describeActions(User user) {
UserType type = user.getType();
UserActuator userActuator = map.get(type);
userActuator.describeActions(user);
}
}
ActuatorContainer λ ν©μ±μ μ΄μ©ν΄μ ꡬννμλ€.
μμ μ§μ νλ λ¬Έμ λ₯Ό ν λ² ν΄κ²°ν΄λ³΄μ
Generic μ μ΄μ©νμ¬ μ°μνκ² μ κ±°νκΈ°
μμμ μ§μ ν λ¬Έμ κ° λμλκ°?
λ€μ μ νν μ μνμλ©΄ μ΄κ²μ΄λ€.
Actuator λ μ»΄νμΌ μμ μ μ¬λ°λ₯΄μ§ μμ νμ μ User κ° λ€μ΄μ€λ κ²μ μ ννλ€
μ΄λ₯Ό μν΄μ Generic μ μ΄μ©ν μ μλ€.
UserActuator μμ μ λ€λ¦ μ¬μ©νκΈ°
// Actuator
public interface UserActuator <T extends User> {
void describeActions(T user);
}
μ°μ Actuator μμ User νμ λ§ λ°λλ€λ κ²μ λͺ νν νκΈ° μν΄ Generic Expression μ μ΄μ©νλ€.
User λ₯Ό μμν T λ§ λ°λλ‘ νμ
κ°κ°μ Actuator ꡬν체μ νμ μ§μ νκΈ°
κ·Έλ¦¬κ³ κ°κ°μ Actuator μμ ꡬν체μ νμ μ μ λλ¦μΌλ‘ μ§μ ν΄μ£Όμ.
// Guest Actuator
public class GuestActuator implements UserActuator<Guest> {
@Override
public void describeActions(Guest user) {
user.readArticle();
}
}
// Member Actuator
public class MemberActuator implements UserActuator<Member> {
@Override
public void describeActions(Member user) {
user.readArticle();
user.createArticle();
}
}
// Admin Actuator
public class AdminActuator implements UserActuator<Admin> {
@Override
public void describeActions(Admin user) {
user.readArticle();
user.createArticle();
user.deleteArticle();
}
}
κ·ΈλΌ μ΄λ€κ°?
μμ 보μλ if/else ꡬ문μ κΉλνκ² μμ¨ μ μλ€.
κ·ΈλΌμλ μ‘΄μ¬νλ λ¬Έμ μ
νμ§λ§ μμ λ°©μμλ νκ°μ§ ν° λ¬Έμ μ μ΄ μ‘΄μ¬νλ€.
λ°λ‘, Raw use of parameterized class μ΄λ€.
μ½λλ‘ λ΄λ³΄μ
public class ActuatorContainer implements UserActuator {
private final Map<UserType, UserActuator> map;
public ActuatorContainer() {
this.map = new HashMap<>();
map.put(UserType.GUEST, new GuestActuator());
map.put(UserType.MEMBER, new MemberActuator());
map.put(UserType.ADMIN, new AdminActuator());
}
@Override
public void describeActions(User user) {
UserType type = user.getType();
UserActuator userActuator = map.get(type);
userActuator.describeActions(user);
}
}
μ μ½λμμ 보면 2λ²μ§Έ λΌμΈμμ map μΌλ‘ container λ₯Ό μμ±ν λ, Raw Type μ UserActuator κ° λ€μ΄κ°κ² λλ κ²μ΄λ€.
μ΄ λ§μ Generic Expression μ μ¬μ©ν ν΄λμ€λ₯Ό νΈμΆν λ, λͺ νν νμ μ μ§μ ν΄μ£Όμ§ μμμ λ°μνλ λ¬Έμ μ΄λ€.
κ·ΈλΌ νμ μ μ§μ ν΄μ£Όλ©΄ λμ§ μλλ? λΌκ³ ν μ μμ§λ§ νμ μ μ§μ ν΄λ²λ¦¬λ μκ° νΉμ ꡬνμ κ²°μ λμ΄ λ²λ¦°λ€.
μ¦, UserActuator μ μ λλ¦μ UserType.MEMBER λ‘ μ§μ νλ μκ° map.put(UserType.GUEST, new GuestActuator()) μμ μ»΄νμΌ μλ¬κ° λ°μνκ² λλ€.
λμΌλ‘
μμ§ λ§μ§λ§ λ¬Έμ λ₯Ό ν΄κ²°νμ§ λͺ»νκ³ μ΄μ λΉμ·ν μν©μμλ Raw Type μ μ¬μ©ν΄λ²λ¦¬κ³ μλ€.
μΆνμ μ΄μ κ΄λ ¨νμ¬ λ μλ£λ₯Ό μ°Ύμλ³΄κ³ κ³ λ―Όν΄λ³Έ λ€ κΈμ μμ±ν΄λ³΄κ² λ€.
... TBD
λκΈ