변경에 유리한 코드(1) - 다형성, factory method

 

class Car{}
class SportsCar extends Car{}
class Truck extends Car{}
Car car = getCar();

static Car getCar(){
	return new SportsCar();
}

static Car getCar(){
	return new Truck();
}

 

 

변경에 유리한 코드(2) - Map, 외부 파일

 

Car car = getCar();

static Car getCar() throws Exception {
	// config.txt 를 읽어서 Properties 에 저장
    Properties p = new Properties(); // Map(Object, Object), Properties(Stirng, String)
    p.load(new FileReader("config.txt");
    
    // 클래스 객체(설계도)를 얻어서
    Class clazz = Class.forname(p.getProperty("car"));
    
    return (Car)clazz.newInstance(); // 객체를 생성해서 반환
}
package com.fastcampus.ch3.diCopy1;

import java.io.FileReader;
import java.util.Properties;

class Car {}
class SportsCar extends Car {}
class Truck extends Car {}
class Engine {}

public class Main1 {

    public static void main(String[] args) throws Exception{
        Car car = (Car)getObject("car");
        Engine engine = (Engine) getObject("engine");
        System.out.println("car = " + car);
        System.out.println("engine = " + engine);
    }
    static Object getObject(String key) throws Exception {
        Properties p = new Properties();
        p.load(new FileReader("config.txt"));

        Class clazz = Class.forName(p.getProperty(key));

        return (Object)clazz.newInstance();
    }

//    static Car getCar() throws Exception {
//        Properties p = new Properties();
//        p.load(new FileReader("config.txt"));
//
//        Class clazz = Class.forName(p.getProperty("car"));
//
//        return (Car)clazz.newInstance();
//    }
}

 

 

객체 컨테이너(ApplicationContext) 만들기 

 

package com.fastcampus.ch3.diCopy2;

import java.io.FileReader;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;

class Car {
}

class SportsCar extends Car {
}

class Truck extends Car {
}

class Engine {
}

class AppContext {
	Map map; // 객체 저장소

	AppContext() {
		map = new HashMap<>();
		map.put("car", new SportsCar());
		map.put("engine", new Engine());
	}

	Object getBean(String key) {
		return map.get(key);
	}
}

public class Main2 {

	public static void main(String[] args) throws Exception {
		AppContext ac = new AppContext();

		Car car = (Car) ac.getBean("car");
		Engine engine = (Engine) ac.getBean("engine");
		System.out.println("car = " + car);
		System.out.println("engine = " + engine);
	}


}
car = com.fastcampus.ch3.diCopy2.SportsCar@6f75e721
engine = com.fastcampus.ch3.diCopy2.Engine@69222c14

 

 

package com.fastcampus.ch3.diCopy2;

import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;

class Car {
}

class SportsCar extends Car {
}

class Truck extends Car {
}

class Engine {
}

class AppContext {
	Map map; // 객체 저장소

	AppContext()  {
		

		try {
			Properties p = new Properties();
			p.load(new FileReader("config.txt"));

			// properties 에 있는 내용을 map 에 저장 
			map = new HashMap<>(p);
	
			// 반복문으로 클래스 이름을 얻고 객체를 생성해서 map 에 저장
			for(Object key : map.keySet()) {
				Class clazz = Class.forName((String)map.get(key));
				map.put(key, clazz.newInstance());
				
			}

		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

	}

	Object getBean(String key) {
		return map.get(key);
	}
}

public class Main2 {

	public static void main(String[] args) throws Exception {
		AppContext ac = new AppContext();

		Car car = (Car) ac.getBean("car");
		Engine engine = (Engine) ac.getBean("engine");
		System.out.println("car = " + car);
		System.out.println("engine = " + engine);
	}


}
car = com.fastcampus.ch3.diCopy2.SportsCar@3fb4f649
engine = com.fastcampus.ch3.diCopy2.Engine@33833882

 

 

 

자동 객체 등록하기 - Component Scanning

 

 

 

@Component 어노테이션 사용해서 등록하기

 

package com.fastcampus.ch3.diCopy3;

import org.springframework.stereotype.Component;
import java.awt.Component;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import org.springframework.util.StringUtils;
import com.google.common.reflect.ClassPath;


@Component
class Car {
}

@Component
class SportsCar extends Car {
}
@Component
class Truck extends Car {
}
@Component
class Engine {
}

class AppContext {
	Map map; // 객체 저장소

	AppContext()  {
		
		map = new HashMap();
		doComponentScan();
		

	}

	private void doComponentScan() {
		try {
			// 1. 패키지내의 클래스 목록을 가져온다.
			// 2. 반복문으로 클래스를 하나씩 읽어와서 @Component 가 붙어 있는지 확인
			// 3. @Component 가 붙어 있으면 객체를 생성해서 map 에 저장
			ClassLoader classLoader = AppContext.class.getClassLoader();
			ClassPath classPath = ClassPath.from(classLoader);
			Set<ClassPath.ClassInfo> set = classPath.getTopLevelClasses("com.fastcampus.ch3.diCopy3");
			
			for (ClassPath.ClassInfo classInfo : set) {
				Class clazz = classInfo.load();
				Component component = (Component) clazz.getAnnotation(Component.class);
				
				if (component!=null) {
					String id = StringUtils.uncapitalize(classInfo.getSimpleName());
					map.put(id, clazz.newInstance());
					
				}
			}
		} catch (Exception e) {
			e.printStackTrace();
		} 
	}

	Object getBean(String key) {
		return map.get(key);
	}
}

public class Main3 {

	public static void main(String[] args) throws Exception {
		AppContext ac = new AppContext();

		Car car = (Car) ac.getBean("car");
		Engine engine = (Engine) ac.getBean("engine");
		System.out.println("car = " + car);
		System.out.println("engine = " + engine);
	}


}

 


객체 찾기 - by name, by type

 

package com.fastcampus.ch3.diCopy3;

import org.springframework.stereotype.Component;
import java.awt.Component;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import org.springframework.util.StringUtils;
import com.google.common.reflect.ClassPath;


@Component
class Car {
}

@Component
class SportsCar extends Car {
}
@Component
class Truck extends Car {
}
@Component
class Engine {
}

class AppContext {
	Map map; // 객체 저장소

	AppContext()  {
		
		map = new HashMap();
		doComponentScan();
		

	}

	private void doComponentScan() {
		try {
			// 1. 패키지내의 클래스 목록을 가져온다.
			// 2. 반복문으로 클래스를 하나씩 읽어와서 @Component 가 붙어 있는지 확인
			// 3. @Component 가 붙어 있으면 객체를 생성해서 map 에 저장
			ClassLoader classLoader = AppContext.class.getClassLoader();
			ClassPath classPath = ClassPath.from(classLoader);
			Set<ClassPath.ClassInfo> set = classPath.getTopLevelClasses("com.fastcampus.ch3.diCopy3");
			
			for (ClassPath.ClassInfo classInfo : set) {
				Class clazz = classInfo.load();
				Component component = (Component) clazz.getAnnotation(Component.class);
				
				if (component!=null) {
					String id = StringUtils.uncapitalize(classInfo.getSimpleName());
					map.put(id, clazz.newInstance());
					
				}
			}
		} catch (Exception e) {
			e.printStackTrace();
		} 
	}

	Object getBean(String key) {
		return map.get(key);
	}
	Object getBean(Class clazz) {
		for(Object obj : map.values()) {
			if (clazz.isInstance(obj)) {
				return obj;
			}
		}
		return null;
	}
}

public class Main3 {

	public static void main(String[] args) throws Exception {
		AppContext ac = new AppContext();

		Car car = (Car) ac.getBean("car"); // byName 으로 객체를 검색
		Car car2 = (Car) ac.getBean(Car.class); // byType 으로 객체를 검색

		Engine engine = (Engine) ac.getBean("engine");
		System.out.println("car = " + car);
		System.out.println("engine = " + engine);
	}


}

 

 

객체를 자동 연결하기 - @Autowired (byType)

 

package com.fastcampus.ch3.diCopy4;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import org.springframework.util.StringUtils;
import com.google.common.reflect.ClassPath;


@Component
class Car {
	@Autowired Engine engine;
	@Autowired Door door;
	
	@Override
	public String toString() {
		return "Car [engine=" + engine + ", door=" + door + "]";
	}
	
	
}

@Component
class SportsCar extends Car {
}
@Component
class Truck extends Car {
}
@Component
class Engine {
}
@Component
class Door {
}

class AppContext {
	Map map; // 객체 저장소

	AppContext()  {
		
		map = new HashMap();
		doComponentScan();
		doAutowired();

		

	}

	private void doAutowired() {
		try {
			// map 에 저장된 객체의 iv 중에 @Autowired 가 붙어 있으면
			// map 에서 iv 의 타입에 맞는 객체를 찾아서 연결(객체의 주소를 iv 저장)
			for (Object bean : map.values()) {
				for(Field fld : bean.getClass().getDeclaredFields()) {
					if(fld.getAnnotation(Autowired.class)!=null) // byType {
						fld.set(bean, getBean(fld.getType())); // car.engine = obj;
					}
				}
		} catch (Exception e) {
			e.printStackTrace();
		}
		}
	

	private void doComponentScan() {
		try {
			// 1. 패키지내의 클래스 목록을 가져온다.
			// 2. 반복문으로 클래스를 하나씩 읽어와서 @Component 가 붙어 있는지 확인
			// 3. @Component 가 붙어 있으면 객체를 생성해서 map 에 저장
			ClassLoader classLoader = AppContext.class.getClassLoader();
			ClassPath classPath = ClassPath.from(classLoader);
			Set<ClassPath.ClassInfo> set = classPath.getTopLevelClasses("com.fastcampus.ch3.diCopy4");
			
			for (ClassPath.ClassInfo classInfo : set) {
				Class clazz = classInfo.load();
				Component component = (Component) clazz.getAnnotation(Component.class);
				
				if (component!=null) {
					String id = StringUtils.uncapitalize(classInfo.getSimpleName());
					map.put(id, clazz.newInstance());
					
				}
			}
		} catch (Exception e) {
			e.printStackTrace();
		} 
	}

	Object getBean(String key) {
		return map.get(key);
	}
	Object getBean(Class clazz) {
		for(Object obj : map.values()) {
			if (clazz.isInstance(obj)) {
				return obj;
			}
		}
		return null;
	}
}

public class Main4 {

	public static void main(String[] args) throws Exception {
		AppContext ac = new AppContext();

		Car car = (Car) ac.getBean("car"); // byName 으로 객체를 검색
		Engine engine = (Engine) ac.getBean("engine");
		Door door = (Door) ac.getBean(Door.class); // byType 으로 객체를 검색

		// 수동으로 객체를 연결
//		car.engine =engine;
//		car.door= door;
		
		System.out.println("car = " + car);
		System.out.println("door = " + door);
	}


}
car = Car [engine=com.fastcampus.ch3.diCopy4.Engine@262b2c86, door=com.fastcampus.ch3.diCopy4.Door@371a67ec]
door = com.fastcampus.ch3.diCopy4.Door@371a67ec

 

 

 

객체를 자동 연결하기 - @Resource (byName)

 

package com.fastcampus.ch3.diCopy4;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;

import javax.annotation.Resource;

import org.springframework.util.StringUtils;
import com.google.common.reflect.ClassPath;


@Component
class Car {
	@Resource Engine engine;
	@Resource Door door;
	
	@Override
	public String toString() {
		return "Car [engine=" + engine + ", door=" + door + "]";
	}
	
	
}

@Component
class SportsCar extends Car {
}
@Component
class Truck extends Car {
}
@Component
class Engine {
}
@Component
class Door {
}

class AppContext {
	Map map; // 객체 저장소

	AppContext()  {
		
		map = new HashMap();
		doComponentScan();
		doAutowired();
		doResource();

		

	}

	private void doResource() {
		try {
			// map 에 저장된 객체의 iv 중에 @Resource 가 붙어 있으면
			// map 에서 iv 의 타입에 맞는 객체를 찾아서 연결(객체의 주소를 iv 저장)
			for (Object bean : map.values()) {
				for(Field fld : bean.getClass().getDeclaredFields()) {
					if(fld.getAnnotation(Resource.class)!=null) // buName {
						fld.set(bean, getBean(fld.getName())); // car.engine = obj;
					}
				}
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	private void doAutowired() {
		try {
			// map 에 저장된 객체의 iv 중에 @Autowired 가 붙어 있으면
			// map 에서 iv 의 타입에 맞는 객체를 찾아서 연결(객체의 주소를 iv 저장)
			for (Object bean : map.values()) {
				for(Field fld : bean.getClass().getDeclaredFields()) {
					if(fld.getAnnotation(Autowired.class)!=null) // byType {
						fld.set(bean, getBean(fld.getType())); // car.engine = obj;
					}
				}
		} catch (Exception e) {
			e.printStackTrace();
		}
		}
	

	private void doComponentScan() {
		try {
			// 1. 패키지내의 클래스 목록을 가져온다.
			// 2. 반복문으로 클래스를 하나씩 읽어와서 @Component 가 붙어 있는지 확인
			// 3. @Component 가 붙어 있으면 객체를 생성해서 map 에 저장
			ClassLoader classLoader = AppContext.class.getClassLoader();
			ClassPath classPath = ClassPath.from(classLoader);
			Set<ClassPath.ClassInfo> set = classPath.getTopLevelClasses("com.fastcampus.ch3.diCopy4");
			
			for (ClassPath.ClassInfo classInfo : set) {
				Class clazz = classInfo.load();
				Component component = (Component) clazz.getAnnotation(Component.class);
				
				if (component!=null) {
					String id = StringUtils.uncapitalize(classInfo.getSimpleName());
					map.put(id, clazz.newInstance());
					
				}
			}
		} catch (Exception e) {
			e.printStackTrace();
		} 
	}

	Object getBean(String key) {
		return map.get(key);
	}
	Object getBean(Class clazz) {
		for(Object obj : map.values()) {
			if (clazz.isInstance(obj)) {
				return obj;
			}
		}
		return null;
	}
}

public class Main4 {

	public static void main(String[] args) throws Exception {
		AppContext ac = new AppContext();

		Car car = (Car) ac.getBean("car"); // byName 으로 객체를 검색
		Engine engine = (Engine) ac.getBean("engine");
		Door door = (Door) ac.getBean(Door.class); // byType 으로 객체를 검색

		// 수동으로 객체를 연결
//		car.engine =engine;
//		car.door= door;
		
		System.out.println("car = " + car);
		System.out.println("door = " + door);
	}


}
car = Car [engine=com.fastcampus.ch3.diCopy4.Engine@6fb0d3ed, door=com.fastcampus.ch3.diCopy4.Door@6dde5c8c]
door = com.fastcampus.ch3.diCopy4.Door@6dde5c8c

 

'Spring > Ch3. Spring DI, AOP' 카테고리의 다른 글

Spring - AOP  (0) 2022.09.30
Spring - Transaction  (0) 2022.09.29
Spring - Spring DI(1)  (0) 2022.09.13
Ch3-3_Spring DI 활용하기 - 이론  (0) 2022.02.08
Ch3-2_Spring DI 흉내내기(2)  (0) 2022.02.07
복사했습니다!