IOC 

Inversion of Control

제어권이 뒤바뀐다.

원래는 자기가 사용할 의존성은 자기가 만들어 사용한다.

Ex) new로 생성해서 사용하는 것

 

Ioc는 사용하지만 만들지 않는다. 즉 누군가가 생성해준다.

누군가란? 스프링

Ex) new를 사용하지 않는다.

 

의존성 주입 예제

 

스프링에서 의존성을 주입해준다.(생성자 방식)

private final OwnerRepository owners;
public OwnerController(OwnerRepository clinicService, VisitRepository visits) { 
	this.owners = clinicService; 
    //vistis 는 생략 this.visits = visits;
}

 

만약 IoC가 적용 안되었다면?

이런 식으로 사용하면 원래 Null point Exception 에러가 난다.

 

Spring이 관리하는 객체를 Bean이라고 함.

즉, 스프링이 빈 객체를 생성해 주입해줘서 동작되게 한다.

 

결론 : IoC에서 객체 생성은 내가 하는 것이 아닌 스프링이 필요한 의존성을 주입해준다. 

 

IOC 컨테이너(Bean Factory) ApplicationContext

Bean Factory이 IOC 컨테이너인데 ApplicationContext는 BeanFactory를 상속받는다.

 

IOC컨테이너 역할

bean 생성하고 bean들 사이에 의존성을 엮어주고 스프링에 제공해준다.

 

OwnerController, OwnerRepository 등 즉 컨트롤러, 레파지토리 등은 빈으로 등록해 사용한다.

 

모든 클래스가 다 무조건 bean으로 등록되는 것이 아니다.

 

@Controller 등

@으로 등록하는 방식,

extends Repository 상속하는 방식,

@Bean으로 등록하는 방식 등

여러 가지 방법으로 Bean으로 설정이 가능하다.

 

의존성 주입은 bean끼리만 사용한다. 예외의 경우 다른 객체에 할 수 있지만 거의 하지 않는다.

즉, 주로 IOC컨테이너 안에 있는 객체에만 서로 의존성 주입을 한다.

 

IOC컨테이너는 매번 새로 객체를 생성하는 것이 아니라 생성된 객체를 같이 사용한다.

 

Bean

IoC 컨테이너가 관리하는 객체를 말한다. 

ApplicationContext가 만들어서 그 안에 담고 있는 객체를 말한다.

Component Scannig

-@Controller

-@Service

-@Repository

-@Component

등 여러 가지 등을 찾아서 bean으로 등록한다.

 

ex)

public interface OwnerRepository extends Repository<Owner, Integer>

Repository를 보면 특정한 @이 없더라도 특정 인터페이스를 상속받는 클래스를 찾아서 

내부에서 인터페이스를 구현하고 Bean으로 등록한다.

 

직적 Bean으로 등록

@Configuration과 @Bean으로 등록할 수 있다.

@Configuration(proxyBeanMethods = false)

@EnableCaching

class CacheConfiguration {



@Bean

public JCacheManagerCustomizer petclinicCacheConfigurationCustomizer() {

return cm -> {

cm.createCache("vets", cacheConfiguration());

};

}

}

 

 

@Autowried로 IoC컨테이너에서 객체를 꺼내 사용할 수 있다.

 

 

의존성 주입(Dependency Injection)

 

@Autowried로 보통 주입을 한다.

생성자

스프링 4.3부터 이상부턴 생성자에서 생략하고 사용할 수 있다.

public OwnerController(OwnerRepository clinicService, VisitRepository visits) {

this.owners = clinicService;

this.visits = visits;

}

,

필드

@Autowired

private final OwnerRepository owners;

, set

public void setOwners(OwnerRepository r){

this.owners = r;

}

등으로 주입할 수 있다.

 

주의점 : final로 생성하면 무조건 생성하거나 생성자를 만들어야 한다.

 

 

생성자를 생성하자 않고 @Autowried로 생성자 주입도 가능하다. (자주 사용하는 방법)

bean으로 등록되어있지않으면 의존성주입은 불가능하다.

'개발 소발 > 개발 Spring' 카테고리의 다른 글

Spring Autowired와 ComponentScan이란  (0) 2020.07.10
AOP란? AOP 기초개념  (0) 2020.07.09
프레임워크 개념  (0) 2018.01.26
SpringMVC란?  (0) 2018.01.11
MVC패턴이란?  (0) 2018.01.11

신사임당 - 부자가 되는 미묘한 차이 (존리)

 

자본주의에서 부자가 된 사람들 중 월급을 많이 받아서 된 사람은 거의 없다.

하지만 월급으로 초기 자본 즉 시드를 만들어야 한다.

그다음 시드를 이용해야 한다.

자본주의에선 자본이 일하게 하는 것을 하지 않으면 부자가 될 수 없다.

부자란? 돈으로부터 자유로움을 가지는 것이다.


주식에 투자할 땐 변동성을 이겨내야 한다.

변동성이란? 어떤 것이든 항상 올라가진 않는다.

올라갈 때가 있으면 내려갈 때도 있다.

20년을 기다리려고 해도 당장 10만 원이 7만 원이 되면 마음이 아프다.


확신이 없으면 기다릴 수 없다.

확신을 가지려면 경제 공부를 하여야 한다.


예를 들어 a 회사의 주식을 샀다 1년 뒤 1만 원에서 8천 원으로 하락했다면 보통 스트레스 받는다.

하지만 a라는 회사를 분석했다면?

a 회사의 미래가치가 괜찮다면 문제없다.

10년 후 20년 후 회사의 미래가치를 분석하자.


한 종목에 모두 투자하는 것이 아닌 15~20개 종목으로 분산해야 한다.


하루에 만 원씩이라도 20년 동안 투자하면 상당한 큰돈이 된다.

365*20 = 7000 변동이 없으면 7000만 원이지만 그 이상으로 변하게 된다.


투자 방면에선 기회비용 개념으로 보았을 때

전세, 자가, 월 세중에 월세가 유리할 수 있다.

부동산에 관심을 가지는 건 좋지만 부동산에만 집착하지 말자.


부동산은 자기 자본이 적고 대출로 받을 수 있다. 쉽게 생각한다.

하지만 리스크가 크다. 일본을 생각해보자.


부동산과 주식의 가격 상승률의 차이가 있다.

다만 주식도 리스크도 있다. 주식이 무조건 좋은 것은 아니다.


연급 저축 펀드는 월급쟁이도 400만 원은 채우자 환급해준다.

개별 주식 투자보단 400만 원을 무조건 채우자.

단점은 55세까지 깰 수 없다.


5만 원 주식을 사서 10년 뒤에 5배가 올라간다면? 기회비용을 생각해야 한다.

그래프를 보기보단 미래가치를 보고 투자해야 한다.



1. 부자인척하지 말고 가난해 보이더라도 투자하자.

2. 부자가 되는 길이 있다. 부자가 될 수 없다고 미리 포기하지 말자.

3. 돈을 숭배하진 말아야 하지만 돈의 중요성을 알자.

출처 - 신사임당 유튜브

 


신사임당 - 부자는 알지만 가난한 사람은 모르는 것 (존리) 감상평


안빈낙도의 삶으로는 부자가 될 수 없다.

더보기

安貧樂道

①구차(苟且)하고 궁색(窮塞)하면서도 그것에 구속(拘束)되지 않고 평안(平安)하게 즐기는 마음으로 살아감

 

 

 

 




우린 익숙한 것이 아닌 것에 잘 도전하지 않는다.

하지만 도전 하는것과 도전하지 않는 것은 차이가 있다.

나무를 심는 것과 심지 않는 것은 엄청난 차이가 있다.

한그루 한그루 심다 보면 숲이 되어있을 것이다.


돈은 쓰는 걸 버릇들이는버릇 들이는 게 아니라 저축하는 것을 버릇 들이는 것이다.


왜 주변에는 쓰는 걸 버릇들이는 사람이 더 많을까?

우리나라는 경제교육을 너무 하지 않기 때문이다.

스스로 생각해봐도 어렸을 때부터 경제 교육을 받은 기억이 없다.


경제 교육은 꼭 받아야 한다.

금융 문맹에서 벗어나야 하기 때문이다.

금융 문맹은 집단적으로 가난하게 만드는 경향이 있다.


경제 교육을 받지 않고 금융 문맹이 된다면

나는 부자는 어차피 안돼! 그냥 쓰자 마인드를 가지게 된다.

이런 마인드가 안빈낙도의 마인드 아닐까 생각해본다.

 


요새 한국 사람은 상처를 많이 받아서 그런지

포기하는 게 빠르고 금융지식을 쌓지 않는다.

YOLO 족을 욕하는 것이 아닌 적당한 미래 준비는 해야 한다.


부자는 하루아침에 되지 않는다.

천천히 돼가는 것이다.

나무 한그루 한그루 심으면 숲이 되는 과정을 생각해보자.

 

 



많이들 하는 예이지만,

눈사람이 만들어질 때를 생각해보자.

처음엔 작은 눈을 굴리지만 점차 커진다.


지금부터 시작해야 한다. 

빚을 없애야 하고 라이프 스타일을 바꾸어야 한다.


어떻게 바꾸어야 할까?


근로소득으로 부자가 된다는 건 거의 불가능하다.

자본주의에서는 부자가 되려고 열망해야 한다.


흙 수저가 부자가 되려면 근로소득으로 새로운 창업을 해야 한다.

부자가 되려면 창업은 좋은 방법 중에 하나이다.

하지만 우린 창업을 도전하기엔 리스크가 크다.


새로운 방식의 창업의 대안이 있을까?

주식투자도 창업으로 볼 수 있다.

주식투자는 동업으로 생각할 수 있다.


사람들이 착각하는 것이 있다.

10만 원이 8만 원이 되는 것은 위험이 아닌 변동이다.

물론 투자 후 10년이 지났을 때 0에 가까이한다면 위험이다.


주식투자는 리스크가 있지만 위험이 많은 종목에 투자하지 않으면

0%로 될 일은 거의 없다.

나만이 일하는 게 아닌 나의 자본도 일하게 하는 개념을 생각하자.


금융지식의 중요성의 이유

모든 투자엔 충분한 공부가 필요하다.


주식투자는 도박적으로 하지 않는 게 아닌 자신이 알고 싶은 종목을 알아가는 게 좋다.

하고 싶은 사업 되고 싶은 꿈과 관련된 기업을 알아보고 주식을 접근해보자

아이들에게 선물해주는 것도 좋다.




1. 부자는 금방 되는 것이 아닌 천천히 돼가는 것이다.

2. 부자가 되기 위해선 금융지식은 필수이다.

3. 지금 당장 시작해라. 지금도 늦었다.

4. 자본도 스스로 일하게 하라.

출처 - 신사임당 유튜브






다형성은 편리하고 유용하지만
모든 경우에 사용할 수 없다.

출력연산자가 대표적인 경우이다.

출력연산자를 사용하려면 함수를 따로 하나 생성하여 오버라이딩 한다.
즉, 함수에게 기능을 위임한다.

비슷한 전략이 다른경우에도 사용될 수 있다.

 

핵심. 새로운 가상함수를 이용해 문제점을 해결한다.

#include <iostream>

using namespace std;

class Base
{
public:
	Base() {};

	friend ostream& operator << (ostream &out, const Base &b)
	{
		return b.print(out);
	}

	virtual ostream& print(ostream& out) const
	{
		out << "Base";
		return out;
	}

};

class Derived : public Base
{
public:
	Derived() { };

	virtual ostream& print(ostream& out)const override
	{
		out << "Derived";
		return out;
	}
};
int main() {

	Base b;
	cout << b << endl;

	Derived d;
	cout << d << endl;


	return 0;
}

자식 클래스의 포인터를 부모클래스의 포인터로 바꾼후 다시 자식클래스포인터로 변경하기.

auto와 dynamic_cast를 사용한다.

dynamic_cast는 casting에 실패하면 nullptr을 반환한다.

static_cast도 사용가능하다. static_cast는 할 수 있는한 최대한 변환시킨다.
안되야 될것도 되는 경우가 생긴다. 하지만 사용할 만한 가치는 있다.
static_cast는 nullptr을 반환하지 않는다.

 

#include <iostream>
#include <string>

using namespace std;

class Base
{
public:
	int m_i = 0;
	virtual void print()
	{
		cout << "I'm Base" << endl;
	}

};

class Derived1 : public Base
{
public:
	int m_d = 0;
	virtual void print() override
	{
		cout << "I'm Derived1" << endl;
	}

};

class Derived2 : public Base
{
public:
	int m_d = 0;
	string m_s = "123";
	virtual void print() override
	{
		cout << "I'm Derived2" << endl;
	}

};
int main()
{

	Derived2 d2;
	Base *b = &d2;
	b->print();

	auto *base_to_d2 = dynamic_cast<Derived2*>(b);

	cout << base_to_d2->m_s << endl;


	return 0;
}

상속할때 보통 부모클래스보다는 자식클래스가 정보를 많이 가지고 있다.
이유 : 추가 함수,추가 변수,오버라이딩 등등

작은 부모의 객체에 큰 자식클래스를 대입한다면 다형성이 사라진다.

부모객체로 인식한다고 생각하면된다.

 

즉, 자식에 추가된 데이터들이 사라진다.


reference_wapper를 사용하거 포인터를 사용하면 객체잘림을 막을 수 있다.

 

당연, 포인터를 생각해보면 주소값을 대입하는거니 데이터는 그대로 남아있겠지?

 

#include <iostream>
#include <vector>

using namespace std;

class Base
{
public:
	int m_i = 0;
	virtual void print() 
	{
		cout << "I'm Base" << endl;
	}

};

class Der : public Base
{
public:
	int m_d = 0;
	virtual void print() override 
	{
		cout << "I'm Der" << endl;
	}

};
int main()
{
	Der d;
	Base b = d;
	b.print();
	
	//reference_wrapper를 사용하거나 *포인터 사용이가능하다.
	vector<reference_wrapper<Base>> my_vec;
	my_vec.push_back(b);
	my_vec.push_back(d);

	//reference_wrapper는 ref를 받아오기위해 get()을 사용한다.
	for (auto & a : my_vec)
		a.get().print();

	vector<Base*> my_vec2;
	my_vec2.push_back(&b);
	my_vec2.push_back(&d);

	for (auto & a : my_vec2)
		a->print();
	return 0;
}

다이아몬드 상속문제.

해결하기위해 가상 기본 클래스를 사용한다.
숫자는 class :는 상속을 나타낸다.
아래처럼 상속하면 다이아몬드 구조로 될거 같지만
1class가 두번 생성된다.
1
2 :(상속) 1 , 3 :(상속) 1
4 :(상속) 2,3

상속할때 상속하는 코드에 virtual을 쓰면 한번만 생성된다.
맨 마지막 자식 테이블에서 1class 생성자를 정의해준다.

 

#include <iostream>

using namespace std;
class PowerDevice
{

public:
	int m_power;
	PowerDevice(int power){
		cout << "PowerDevice : " << power << endl;
	}

};

class Scanner : virtual public PowerDevice
{
public:
	Scanner(int scan, int power)
		:PowerDevice(power) {
		cout << "Scanner : " << scan << endl;
	}
};

class Printer : virtual public PowerDevice
{
public:
	Printer(int prin, int power)
		:PowerDevice(power) {
		cout << "Printer : " << prin << endl;
	}
};

class Copier : public Scanner, public Printer
{
public:
	Copier(int scan, int prin, int power)
		:Scanner(scan, power), Printer(prin, power) ,PowerDevice(power){}
};
int main()
{
	Copier c(1, 2, 3);
	//주소값이 다르다.
	cout << &c.Scanner::PowerDevice::m_power << endl;
	cout << &c.Printer::PowerDevice::m_power << endl;
	return 0;
}

다형성을 설계관점을 만든다.

기본클래스에서 자식클래스에게 제약을 걸어준다.

순수 가상 함수
- 자식클래스에서 반드시 오버라이딩 해주어야한다.
- virtual 로 선언되고 마지막이 = 0; 이면 순수 가상 함수
- 별도로 함수를 구현할 수 있다. 호출할 수 없다.

virtual void speak() const = 0;



추상 기본클래스
- 순수 가상함수가 포함이된 클래스
- abstact class는 인스턴스생성이 안된다.

class Animal
{
protected:
	string m_name;

public:
	Animal(string name)
		:m_name(name) {}

public:
	string getName() { return m_name; }

	virtual void speak() const = 0;
};


인터페이스
- 순수 가상 함수로만 이루어진 클래스
- 파라미터를 인터페이스로 받으면 다양하게 
구현된 자식 클래스들을 이용할 수 있다.

class IErrorlog
{
public:
	virtual bool reportError(const char * errorMessage) = 0;

	virtual ~IErrorlog() {}
};


순수 가상 함수가 있는 Class를 상속받으면 무조건 오버라이딩해야한다.

 

#include <iostream>
#include <string>

using namespace std;

class Animal
{
protected:
	string m_name;

public:
	Animal(string name)
		:m_name(name) {}

public:
	string getName() { return m_name; }

	virtual void speak() const = 0;
};

//void Animal::speak() const
//{
//	cout << m_name << " ??? " << endl;
//}

class Cat :public Animal
{
public:
	Cat(string name)
		:Animal(name) {

	}

	void speak() const
	{
		cout << m_name << " Meow " << endl;
	}
};


class Dog :public Animal
{
public:
	Dog(string name)
		:Animal(name) {

	}

	void speak() const
	{
		cout << m_name << " Woof " << endl;
	}
};

class Cow : public Animal
{
public:
	Cow(string name)
		:Animal(name) {

	}

	//void speak() const
	//{
	//	cout << m_name << " Woof " << endl;
	//}

};


//Interface 예제
//자신이 정의하지 않고 순수가상함수만 가지고 있다.
//Interface는 대문자 I를 붙여주는게 관습이다.
class IErrorlog
{
public:
	virtual bool reportError(const char * errorMessage) = 0;

	virtual ~IErrorlog() {}
};

class FileErrorLog : public IErrorlog
{
public:
	virtual bool reportError(const char * errorMessage)
	{
		cout << "File Error" << endl;
		return true;
	}

};

//부모클래스를 이용하기에 여러방법이 사용가능하다.
void logTest(IErrorlog & log) {
	log.reportError("Runtime Error!!");
}

int main()
{
	//speak()가 구현이 안되어있다.
	//Cow c("n");

	Cat c("cat");
	c.speak();

	FileErrorLog log;
	logTest(log);

	return 0;
}

'개발 소발 > 개발 C++(기초)' 카테고리의 다른 글

c++ 객체잘림,reference wapper  (0) 2019.09.30
c++ 다이아몬드 상속문제 해결  (0) 2019.09.30
c++ vitual,가상함수  (0) 2019.09.30
c++ 정적,동적바인딩  (0) 2019.09.30
c++ 가상소멸자  (0) 2019.09.23

virtual 함수 (가상함수)는 정적이 아닌 동적으로 실행된다.

함수를 실행시 virtual펑션 테이블(포인터)을 찾고 테이블안에 함수 포인터를 사용한다.


다형성 사용시 자식 클래스에도 virtual펑션 테이블(포인터)가 생긴다.
동적바인딩 될때 오버라이딩된 함수는 자식 테이블 함수 주소 값을 가진다.

virtual을 사용하면 sizeof()로 확인시  포인터 메모리까지 할당되는 걸 볼 수 있다.

 

#include <iostream>

using namespace std;

class Base
{
public:
	virtual void fun1() {};
	void fun2() {};
};

class Der : Base
{
public:
	void fun1() {};
	void fun3() {};

};

int main()
{
	cout << sizeof(Base) << endl;
	cout << sizeof(Der) << endl;
	return 0;
}

가상함수의 내부동작 이해

속도면에선 static,dynamic중에 static이 빠르다.

정적 바인딩은 프로그램이 실행될때 메모리에 배치된다.
동적 바인딩은 그때 그때 배치된다.

 

dynamic바인딩이란? 

쉽게말해 함수 포인터로 동적할당해 그때그때 맞게 함수 주소를 대입한다.


dynamic은 포인터로 주소를 타고 가야한다.
하지만 dynamic 즉 동적바인딩을 쓰면 프로그래밍이 유연해진다.

 

#include <iostream>

using namespace std;

int add(int x, int y) {
	return x + y;
}

int subtract(int x, int y) {
	return x - y;
}

int multiply(int x, int y) {
	return x * y;
}
int main()
{
	int x, y;
	cin >> x >> y;

	int op;
	cout << "0 : add, 1 : subtract, 2 : multiply" << endl;

	cin >> op;
	// statuc binding (early binding)
	/*int result;
	switch (op) 
	{
	case 0: result = add(x, y); break;
	case 1: result = subtract(x, y); break;
	case 2: result = multiply(x, y); break;
	}
	cout << result << endl;
	*/

	//Dynamic binding (late binding)
	int(*func_ptr)(int, int) = nullptr;
	switch (op) {
		case 0: func_ptr = add; break;
		case 1: func_ptr = subtract; break;
		case 2: func_ptr = multiply; break;
	}
	cout << func_ptr(x, y) << endl;
	return 0;
}

+ Recent posts