반응형

사경인 회계사님이 쓴 재무제표 모르면 주식투자 절대로 하지마라에 나오는 공식인 S-RIM을 계산하여 해당하는 종목을 매주 제공합니다.

 

재무제표 정보를 제공하는 사이트(http://comp.fnguide.com)를 크롤링하여 필요한 정보를 구했습니다.

 

특히, ROE 같은 경우는  당해에 컨센서스가 추측하는 ROE를 기준으로 하였고, 컨센서스가 존재하지 않을 경우 대상에서 제외합니다.

 

목표 수익률은 9%로 하였습니다.

 

당기순이익이 어떠한 이유로 인해(투자, 매각 등) 너무 높아 ROE가 비정상적으로 다른 해보다 높은 기업이 존재합니다.

따라서 아래 종목 리스트는 투자에 참고만 해주시고, 반드시 해당 기업의 재무제표를 다시 확인해주시기 바랍니다.

 

종목명 시가총액 현재가격 매수가격 중간가격 매도가격 지난주 대비
NAVER 674301 410500 513160 781534 1646294 0.86
기아 356720 88000 92825 102224 132510 3.41
POSCO 248482 285000 614835 671168 852684 -3.72
KB금융 229110 55100 110688 112756 119422 -2.65
신한지주 194241 37600 90391 91046 93157 -1.70
LG 147076 93500 148111 161076 202850 2.52
하나금융지주 131506 43800 111576 114243 122837 -2.67
HMM 108240 26700 32903 48909 100483 0.19
우리금융지주 96832 13300 35007 35921 38867 0.38
롯데케미칼 75235 219500 438643 462760 540468 -2.23
LG디스플레이 72815 20350 36972 38911 45158 3.30
한화솔루션 70486 36850 46263 49335 59236 -9.79
LG유플러스 61781 14150 17631 17840 18514 -1.39
CJ제일제당 57432 381500 410540 431159 497596 0.40
미래에셋증권 56098 8830 16682 17304 19310 1.73
현대제철 56047 42000 130331 132275 138539 -5.51
금호석유 52100 171000 280444 384012 717730 -0.58
한국금융지주 48370 86800 163842 201231 321707 -0.23
삼성증권 41926 46950 75658 84260 111976 -0.85
DB손해보험 41135 58100 95016 98714 110628 -1.86
GS 39164 42150 105366 111583 131615 -0.24
NH투자증권 38466 12950 23885 26205 33681 -1.52
GS건설 35687 41700 54443 56281 62200 0.84
메리츠증권 31428 4610 8329 9197 11996 -1.07
팬오션 30791 5760 6711 7450 9829 -4.32
OCI 28738 120500 139554 163030 238675 -6.95
KCC 28037 315500 609006 614478 632112 -5.25
키움증권 27793 106000 206447 250326 391713 0.96
BNK금융지주 27509 8440 27969 28117 28595 -4.09
포스코인터내셔널 25415 20600 28671 30111 34751 -5.07
대우건설 25145 6050 8928 10169 14165 -3.20
효성티앤씨 24495 566000 692221 1026344 2102964 -5.19
한화 24324 32450 71859 78861 101423 -3.13
현대해상 22574 25250 51675 51686 51718 -3.81
코오롱인더 22538 81900 88018 90138 96969 new
두산 22059 133500 151558 182579 282538 29.61
롯데정밀화학 20975 81300 94400 113006 172959 -4.47
효성 20902 99200 145470 168831 244103 -3.69
영원무역 19298 43550 46334 47806 52548 -2.46
JB금융지주 16547 8400 21828 23126 27311 -5.29
DGB금융지주 16526 9770 31257 31477 32188 -5.60
HDC현대산업개발 16312 24750 46027 47850 53727 -3.13
현대두산인프라코어 15765 8100 14001 15004 18233 88.80
동국제강 15269 16000 31768 37405 55570 -6.16
DL 13391 63900 301465 383482 647758 new
SK가스 11907 129000 229510 236217 257828 -6.18
대한유화 11765 181000 317188 323413 343472 -2.16
한섬 10591 43000 48090 48688 50616 2.01
유니드 10268 115500 153307 187838 299104 -0.86
LX인터내셔널 10233 26400 50838 59630 87959 -2.76
GS홈쇼핑 10165 154900 198218 205333 228258 0.00
풍산 8996 32100 65135 71938 93860 -3.02
대한해운 8666 2715 4093 4635 6380 -3.72
동원산업 8642 235000 381471 393173 430880 3.29
대상 8246 23800 34478 35679 39547 -0.22
현대건설기계 8018 40700 71864 74673 83725 1.11
동원F&B 7834 203000 217479 228290 263124 -0.97
세아베스틸 7477 20850 52082 54875 63875 -3.70
SNT모티브 7326 50100 57690 59005 63242 -0.39
SK디앤디 6646 29950 31661 35622 48384 -5.07
코오롱글로벌 6177 24500 32615 40526 66018 -5.77
한국토지신탁 5732 2270 3994 4164 4712 -2.98
국도화학 5505 61100 110750 140779 237540 -8.68
매일유업 5467 69700 70571 78044 102122 -1.14
한국자산신탁 5412 4365 7464 8207 10600 -1.01
한라홀딩스 5231 49950 99092 104989 123987 -1.86
한진 4963 33200 104108 117894 162315 -4.17
SIMPAC 4587 7010 7782 8040 8873 new
태영건설 4201 10800 21827 24885 34736 -2.71
송원산업 4176 17400 23442 25880 33737 new
금호건설 4140 11300 19918 24662 39950 -6.21
대한제강 4067 16500 33895 41984 68048 -11.05
원익머트리얼즈 3984 31600 34042 37365 48069 -2.92
이수화학 3844 13750 18366 24893 45926 -9.55
인탑스 3741 21750 33691 36480 45465 -6.66
동부건설 3297 14500 26456 29723 40249 -3.62
계룡건설 3287 36800 86231 98726 138988 3.11
한세예스24홀딩스 3164 7910 13459 15343 21412 -0.75
랩지노믹스 3057 26700 34235 51552 107351 2.89
풍산홀딩스 2883 27700 106661 125239 185104 -2.83
유니퀘스트 2857 10450 11776 13494 19030 1.46
KPX케미칼 2831 58500 115141 116308 120071 1.36
KSS해운 2736 11800 15851 18081 25269 -0.83
현대코퍼레이션 2361 17850 26782 28272 33075 -3.00
도이치모터스 2281 7700 11274 11887 13860 1.33
금화피에스시 2037 33950 46145 47469 51733 3.66
한라 1991 5260 12502 14387 20460 -6.74
엑시콘 1409 13450 18816 23711 39484 -3.23
SGC이테크건설 1403 69300 149397 196235 347160 0.00
디와이파워 1397 12650 22156 24406 31656 -0.36
현대코퍼레이션홀딩스 1147 12600 22817 24129 28356 -2.71
코메론 1054 11650 19743 20388 22466 -4.09
이노인스트루먼트 850 2110 2280 2418 2862 -2.07
반응형

'주식' 카테고리의 다른 글

[21년 11월 4주차] S-RIM 종목  (0) 2021.11.21
[21년 11월 3주차] S-RIM 종목  (0) 2021.11.14
[21년 11월 1주차] S-RIM 종목  (0) 2021.11.01
[21년 10월 5주차] S-RIM 종목  (0) 2021.10.24
[21년 10월 4주차] S-RIM 종목  (0) 2021.10.19
반응형

자바에서는 new를 사용하여 새로운 객체를 생성한다.

동일한 클래스를 여러 개의 객체를 만들어 사용하는 경우가 많겠지만, 클래스의 용도, 특징에 따라 굳이 객체를 여러 개 만들 필요가 없는 클래스들이 있다.

 

가장 먼저 우리가 자주 사용하는 String이다.

 

String : new vs literal

String 클래스는 두 가지 생성 방식이 있다.

 

1. new

String str = new String("camel");

2. literal

String str = "camel";

 

이 두 가지 방식으로 생성된 String 객체는 기능상으로 다른 점이 있을까? 당연하게도 없다.

하지만 생성된 String 객체가 존재하는 JVM의 위치는 차이가 있다.

 

new를 사용하여 객체를 만들게 되면 어떤 클래스라도 Heap 영역에 객체가 할당된다. 하지만 literal를 사용할 경우 Heap 영역 안에 다른 영역인 String Constant Pool 영역에 String 객체가 할당된다.

 

따라서 아래와 같은 결과가 나타난다.

		String newStr1 = new String("camel");
		String literalStr1 = "camel";

		System.out.println(newStr1 == literalStr1); // false
		System.out.println(newStr1.equals(literalStr1)); // true

기능상으로는 동일하기 때문에 equals는 true를 반환하지만, 객체의 주소 값을 비교하는 ==은 false를 반환한다.

 

그럼 아래의 결과는 어떻게 나올까?

		String newStr1 = new String("camel");
		String newStr2 = new String("camel");

		String literalStr1 = "camel";
		String literalStr2 = "camel";

		System.out.println(newStr1 == newStr2); // false
		System.out.println(literalStr1 == literalStr2); // true

new를 사용하면 항상 객체를 생성하므로 newStr1과 newStr2는 서로 다른 객체이다. 따라서 false가 반환된다.

 

하지만 literal로 선언한 두 값의 비교는 true를 반환하였다. 이유는 무엇일까?

String을 literal로 선언하면 내부적으로 intern() 메서드를 호출하게 된다. intern() 메서드는 주어진 문자열이 String Constant Pool 영역에 존재하는지 먼저 확인하고, 존재한다면 해당 값을 반환하고 없다면 새롭게 생성하기 때문이다.

 

이처럼 String은 특별한 경우가 아니라면 new를 사용하여 객체를 생성하지 말자.

 

정적 팩토리 메서드를 제공하는 변경 불가능 클래스(Immutable Class)

잘 짜인 정적 팩토리 메서드(규칙 1)를 제공하는 변경 불가능 클래스는 정적 팩토리 메서드를 호출하면 이미 만들어진 객체를 반환한다.

// Boolean.java

    public static final Boolean TRUE = new Boolean(true);
    public static final Boolean FALSE = new Boolean(false);

    public static Boolean valueOf(boolean b){
        return b ? TRUE : FALSE;
    }

 

따라서 이런 클래스들은 문서를 잘 읽어보고, new를 사용하여 객체를 생성하지 않아도 되는지 확인하는 것이 좋다.

		Boolean newBool = new Boolean(true); // do not
		Boolean bool = Boolean.valueOf(true); // do it

 

변경 가능한 클래스라도 동일한 값을 가진 객체를 계속 사용할 경우

변경 불가능 클래스라면 동일한 값을 가진 객체를 생성할 필요 없이 재사용하면 된다. 하지만 변경 가능한 클래스라면 해당 객체를 다른 영역에서 변경할 수 있으므로, 필요할 때 객체를 자주 생성해서 사용한다.

 

하지만, 변경되지 않고 해당 영역에서만 사용하고 사라지는 변경 가능한 객체가 있을 수 있다.

아래 예를 보자.

 

	public boolean isBabyBoomer() {
		Calendar gmtCal = Calendar.getInstance(TimeZone.getTimeZone("GMT"));

		gmtCal.set(1946, Calendar.JANUARY, 1, 0, 0, 0);
		Date boomStart = gmtCal.getTime();

		gmtCal.set(1965, Calendar.JANUARY, 1, 0, 0, 0);
		Date boomEnd = gmtCal.getTime();

		return birthDate.compareTo(boomStart) >= 0 && birthDate.compareTo(boomEnd) < 0;
	}

위 코드는 1946년부터 1964년 사이에 태어난 사람인지 확인하는 메서드이다.

 

위 메서드는 어떠한 파라미터도 받지 않고, 항상 동일한 작업을 한다. 하지만 Date 클래스인 boomStart와 boomEnd에 Date 객체는 메서드가 호출될 때마다 새롭게 생성된다.

 

또한 Calendar 클래스는 객체를 생성하는데 비용이 꽤 소요되는 클래스인데, 마찬가지로 항상 새롭게 객체를 생성한다.

위 코드는 아래와 같이 변경하면 약 250배 개선된다.

	private static final Date BOOM_START;
	private static final Date BOOM_END;

	/**
	 * The static initializer block is called only once.
	 */
	static {
		Calendar gmtCal = Calendar.getInstance(TimeZone.getTimeZone("GMT"));

		gmtCal.set(1946, Calendar.JANUARY, 1, 0, 0, 0);
		BOOM_START = gmtCal.getTime();

		gmtCal.set(1965, Calendar.JANUARY, 1, 0, 0, 0);
		BOOM_END = gmtCal.getTime();
	}

	public boolean isBabyBoomerDoThis() {
		return birthDate.compareTo(BOOM_START) >= 0 && birthDate.compareTo(BOOM_END) < 0;
	}

 

API가 객체를 새롭게 생성하는지, 생성하지 않는지 잘 확인하자

위에서 String의 literal 방식, Boolean의 정적 팩토리 메서드 방식, Calendar의 getInstance(), getTime() 등의 예를 들었다. 이렇게 각각의 API들이 객체를 재사용하는지, 아니면 새롭게 만드는지 분명하지 않을 수 있다. 그렇기 때문에 API의 객체를 생성할 때는 항상 문서를 잘 읽고 개발자가 원하는 방식에 맞게 잘 사용해야 한다.

 

아래 예를 들어보자.

	public static void main(String[] args) {
		Map<String, String> map = new HashMap<String, String>();

		map.put("key1", "val1");
		Set<String> keyset1 = map.keySet();

		map.put("key2", "val2");
		Set<String> keyset2 = map.keySet();

		System.out.println(keyset1 == keyset2); // true

	}

Map의 keySet 메서드는 key값의 목록을 Set 클래스로 반환한다. 위처럼 keyset1을 구하고, 새로운 값을 넣은 후 keyset2를 구했을 때, 일반적으로 생각하기에는 두 값이 서로 다를 것으로 생각한다. 그러나 두 keySet의 값은 동일하다. 

 

그러므로 keySet을 여러 번 호출하여 변수를 여러 개 만들어도 큰일 날 것은 없지만, 쓸데없는 짓이다.

 

다음으로는 많이 알려진 AutoBoxing(자동 객체화)의 문제(?)이다.

AutoBoxing은 기본 자료형(Premitive Type)과 그에 대응하는 객체 클래스와 섞어 사용할 수 있도록 해주는 기능이다.

 

아래 예를 들어보자

	public static void main(String[] args) {
		long start = System.currentTimeMillis();

		Long sum = 0L;
		for (long i = 0; i < Integer.MAX_VALUE; i++) {
			sum += i;
		}
	}

Long 클래스인 sum에 기본 자료형인 i의 값을 더하고 있다. 이때 기본 자료형 i는 AutoBoxing이 되어 자동 객체화된다. 즉 loop를 돌 때마다 객체가 계속 생성된다. 그래서 위의 수행 결과는 글쓴이는 9.988초 소요되었다.

 

위와 같이 짠 개발자가 의도한 게 있는지는 모르겠지만(없을 것이다.) 루프는 기본자료형을 사용하고, 최종적인 결과에서만 Long으로 반환하는 것이 맞을 것이다.

	public static void main(String[] args) {
		long start = System.currentTimeMillis();

		long sum = 0L;
		for (long i = 0; i < Integer.MAX_VALUE; i++) {
			sum += i;
		}
	}

 

반응형
반응형

사경인 회계사님이 쓴 재무제표 모르면 주식투자 절대로 하지마라에 나오는 공식인 S-RIM을 계산하여 해당하는 종목을 매주 제공합니다.

 

재무제표 정보를 제공하는 사이트(http://comp.fnguide.com)를 크롤링하여 필요한 정보를 구했습니다.

 

특히, ROE 같은 경우는  당해에 컨센서스가 추측하는 ROE를 기준으로 하였고, 컨센서스가 존재하지 않을 경우 대상에서 제외합니다.

 

목표 수익률은 9%로 하였습니다.

 

당기순이익이 어떠한 이유로 인해(투자, 매각 등) 너무 높아 ROE가 비정상적으로 다른 해보다 높은 기업이 존재합니다.

따라서 아래 종목 리스트는 투자에 참고만 해주시고, 반드시 해당 기업의 재무제표를 다시 확인해주시기 바랍니다.

 

종목명 시가총액 현재가격 매수가격 중간가격 매도가격
NAVER 668552 407000 513160 781534 1646294
기아 344964 85100 92869 102300 132687
POSCO 258073 296000 614095 669898 849705
KB금융 235347 56600 110717 112807 119541
신한지주 197599 38250 90342 90962 92958
LG 143459 91200 148111 161076 202850
하나금융지주 135109 45000 111576 114243 122837
HMM 108037 26650 32903 48909 100483
우리금융지주 96468 13250 35007 35921 38867
한화솔루션 78137 40850 46101 49057 58583
롯데케미칼 76948 224500 438643 462760 540468
LG디스플레이 70490 19700 36972 38911 45158
LG유플러스 62654 14350 17631 17840 18514
현대제철 59317 44450 130366 132336 138681
CJ제일제당 57206 380000 410540 431159 497596
미래에셋증권 55145 8680 16643 17237 19152
금호석유 52404 172000 280444 384012 717730
한국금융지주 48482 87000 161624 197422 312770
삼성증권 42284 47350 75535 84048 111481
DB손해보험 41914 59200 95016 98714 110628
GS 39257 42250 105366 111583 131615
NH투자증권 39060 13150 23885 26205 33681
GS건설 35388 41350 54415 56231 62085
팬오션 32181 6020 6711 7450 9829
메리츠증권 31769 4660 8252 9066 11688
OCI 30885 129500 139554 163030 238675
KCC 29592 333000 609006 614478 632112
BNK금융지주 28682 8800 27984 28143 28657
키움증권 27530 105000 206006 249569 389938
포스코인터내셔널 26772 21700 28671 30111 34751
대우건설 25976 6250 8928 10169 14165
효성티앤씨 25836 597000 683419 1011231 2067513
한화 25111 33500 71037 77449 98111
현대해상 23468 26250 51675 51686 51718
롯데정밀화학 21956 85100 93097 110769 167711
효성 21703 103000 146778 171077 249371
영원무역 19785 44650 46334 47806 52548
DGB금융지주 17507 10350 31257 31477 32188
JB금융지주 17472 8870 21828 23126 27311
두산 17020 103000 151558 182579 282538
HDC현대산업개발 16839 25550 46087 47953 53968
동국제강 16271 17050 31847 37541 55889
에스엘 15787 32750 32893 34220 38494
SK가스 12692 137500 229510 236217 257828
대한유화 12025 185000 317869 324583 346214
LX인터내셔널 10523 27150 50838 59630 87959
한섬 10382 42150 48090 48688 50616
유니드 10357 116500 153307 187838 299104
GS홈쇼핑 10165 154900 198218 205333 228258
풍산 9276 33100 64751 71279 92314
대한해운 9001 2820 3901 4304 5605
동원산업 8367 227500 381471 393173 430880
현대두산인프라코어 8350 10500 14001 15004 18233
대상 8264 23850 34478 35679 39547
현대건설기계 7930 40250 71864 74673 83725
동원F&B 7911 205000 217479 228290 263124
세아베스틸 7764 21650 52042 54807 63714
SNT모티브 7355 50300 57798 59190 63677
SK디앤디 7001 31550 31661 35622 48384
코오롱글로벌 6555 26000 32615 40526 66018
국도화학 6028 66900 110750 140779 237540
한국토지신탁 5908 2340 3994 4164 4712
매일유업 5530 70500 70571 78044 102122
한국자산신탁 5467 4410 7464 8207 10600
한라홀딩스 5330 50900 99092 104989 123987
한진 5179 34650 104108 117894 162315
대한제강 4572 18550 33895 41984 68048
금호건설 4414 12050 19918 24662 39950
태영건설 4318 11100 21827 24885 34736
이수화학 4250 15200 18366 24893 45926
원익머트리얼즈 4104 32550 34042 37365 48069
인탑스 4008 23300 33691 36480 45465
웅진씽크빅 3864 3345 3391 3578 4179
코리아써키트 3720 15750 15867 16467 18402
동부건설 3421 15050 26456 29723 40249
계룡건설 3188 35700 86231 98726 138988
한세예스24홀딩스 3188 7970 13459 15343 21412
랩지노믹스 2971 25950 34235 51552 107351
풍산홀딩스 2967 28500 106661 125239 185104
유니퀘스트 2816 10300 11776 13494 19030
KPX케미칼 2793 57700 115141 116308 120071
KSS해운 2759 11900 15851 18081 25269
현대코퍼레이션 2434 18400 26850 28389 33350
도이치모터스 2251 7600 11274 11887 13860
한라 2135 5640 12396 14204 20032
금화피에스시 1965 32750 46145 47469 51733
엑시콘 1456 13900 18816 23711 39484
SGC이테크건설 1403 69300 149397 196235 347160
디와이파워 1402 12700 22156 24406 31656
현대코퍼레이션홀딩스 1179 12950 22817 24129 28356
코메론 1099 12150 19743 20388 22466
이노인스트루먼트 868 2155 2280 2418 2862
           
           
           
           
           
           

 

반응형

'주식' 카테고리의 다른 글

[21년 11월 3주차] S-RIM 종목  (0) 2021.11.14
[21년 11월 2주차] S-RIM 종목  (0) 2021.11.07
[21년 10월 5주차] S-RIM 종목  (0) 2021.10.24
[21년 10월 4주차] S-RIM 종목  (0) 2021.10.19
[21년 10월 3주차] S-RIM 종목  (0) 2021.10.10
반응형

개인적으로 규칙 3과 규칙 4의 순서가 바뀌는 것이 좋다고 생각함.

 

클래스가 private 생성자만을 가지고 있다면 자신만이 객체를 생성할 수 있기 때문에 규칙 3. 싱글턴 패턴에서 private 생성자를 사용하였다. 또한 싱글턴은 메모리에 올려야 하는 정보(필드)가 있기 때문에 객체를 만들어서 사용한다.

 

싱글턴과는 다르게 메모리에 올려서 사용할 정보들은 없는 Util 클래스들은 객체를 만들 목적의 클래스가 아니다. 따라서 Util 클래스를 작성할 때는 private 생성자를 사용하여 객체 생성을 막는 것이 좋다.

 

아래는 private 생성자를 사용한 Netty의 io.netty.util.internal.StringUtil 소스코드이다.

public final class StringUtil {

    public static final String EMPTY_STRING = "";
    public static final String NEWLINE = SystemPropertyUtil.get("line.separator", "\n");

    public static final char DOUBLE_QUOTE = '\"';
    public static final char COMMA = ',';
    public static final char LINE_FEED = '\n';
    public static final char CARRIAGE_RETURN = '\r';
    public static final char TAB = '\t';
    public static final char SPACE = 0x20;

    private static final String[] BYTE2HEX_PAD = new String[256];
    private static final String[] BYTE2HEX_NOPAD = new String[256];
    private static final byte[] HEX2B;

    ...
    
    // private 생성자를 사용하여 객체 생성을 막는다. 
    private StringUtil() {
        // Unused.
    }

 

private 생성자가 아닌 클래스를 abstract로 선언하여 객체를 생성하지 못하도록 막을 수도 있다. 하지만 해당 클래스는 상속받은 하위 클래스를 만들게 된다면 객체가 결국에 생성되는 것이니 올바른 방법이 아니다.

 

아래는 abstract 클래스로 선언하여 사용한 Spring의 org.springframework.util.StringUtils 소스코드이다.

// abstract로 선언하여 직접적으로 객체는 만들 수 없지만, 상속 받은 하위클래스는 객체 생성이 가능하다.
public abstract class StringUtils {

	private static final String[] EMPTY_STRING_ARRAY = {};

	private static final String FOLDER_SEPARATOR = "/";

	private static final String WINDOWS_FOLDER_SEPARATOR = "\\";

	private static final String TOP_PATH = "..";

	private static final String CURRENT_PATH = ".";

	private static final char EXTENSION_SEPARATOR = '.';
    
    ...

 

/**
 * Spring의 StringUtils는 클래스는 객체 생성을 막기 위해 abstract를 클래스로 만들었지만
 * 하위 클래스가 상속받는다면 객체 생성이 가능
 *
 * @author gwon
 * @history
 *          2021. 10. 24. initial creation
 */
public class ChildSpringStringUtils extends StringUtils {

	public static void main(String[] args) {
		StringUtils stringUtils = new ChildSpringStringUtils();

		stringUtils.isEmpty("abc");
	}
}

 

 

반응형
반응형

사경인 회계사님이 쓴 재무제표 모르면 주식투자 절대로 하지마라에 나오는 공식인 S-RIM을 계산하여 해당하는 종목을 매주 제공합니다.

 

재무제표 정보를 제공하는 사이트(http://comp.fnguide.com)를 크롤링하여 필요한 정보를 구했습니다.

 

특히, ROE 같은 경우는  당해에 컨센서스가 추측하는 ROE를 기준으로 하였고, 컨센서스가 존재하지 않을 경우 대상에서 제외합니다.

 

목표 수익률은 9%로 하였습니다.

 

당기순이익이 어떠한 이유로 인해(투자, 매각 등) 너무 높아 ROE가 비정상적으로 다른 해보다 높은 기업이 존재합니다.

따라서 아래 종목 리스트는 투자에 참고만 해주시고, 반드시 해당 기업의 재무제표를 다시 확인해주시기 바랍니다.

 

종목명 시가총액 현재가격 매수가격 중간가격 매도가격
NAVER 669373 407500 512701 780744 1644441
기아 338073 83400 92386 101469 130739
POSCO 264612 303500 592496 632810 762708
KB금융 239505 57600 110747 112858 119661
SK텔레콤 224828 312000 370223 381915 419590
신한지주 206898 40050 90391 91046 93157
LG 148807 94600 148111 161076 202850
하나금융지주 138562 46150 110743 112813 119482
HMM 117361 28950 39189 58136 119188
우리금융지주 92828 12750 34449 34963 36618
한화솔루션 81963 42850 45603 48202 56577
롯데케미칼 81404 237500 438085 461800 538218
LG유플러스 64837 14850 17636 17848 18533
LG디스플레이 63691 17800 36650 38359 43863
CJ제일제당 59313 394000 410540 431159 497596
미래에셋증권 56162 8840 16643 17237 19152
금호석유 54385 178500 280369 383883 717427
한국금융지주 48816 87600 160052 194723 306441
DB손해보험 46799 66100 95016 98714 110628
삼성증권 43087 48250 76097 85013 113744
GS 40790 43900 105366 111583 131615
NH투자증권 36865 13100 23862 26166 33589
GS건설 35302 41250 54730 56772 63353
메리츠증권 33541 4920 8262 9083 11728
팬오션 32823 6140 6355 6839 8396
KCC 31280 352000 609006 614478 632112
키움증권 28317 108000 206207 249913 390745
포스코인터내셔널 27451 22250 28885 30478 35610
대우건설 27306 6570 9125 10506 14957
효성티앤씨 26096 603000 683419 1011231 2067513
현대해상 25613 28650 51675 51686 51718
한화 25186 33600 71037 77449 98111
효성 22335 106000 146778 171077 249371
영원무역 20317 45850 46151 47491 51810
DGB금융지주 18014 10650 31078 31170 31465
JB금융지주 17709 8990 21695 22899 26778
HDC현대산업개발 17103 25950 47466 50322 59524
동국제강 16319 17100 31847 37541 55889
두산 15929 96400 151558 182579 282538
DL 14250 68000 302910 385963 653578
SK가스 13245 143500 229510 236217 257828
대한유화 13195 203000 323656 334520 369524
유니드 10979 123500 154525 189930 304011
LX인터내셔널 10969 28300 50838 59630 87959
한섬 10689 43400 48090 48688 50616
GS홈쇼핑 10165 154900 198218 205333 228258
풍산 9500 33900 63278 68749 86378
대한해운 9017 2825 3784 4104 5134
동원산업 8459 230000 381471 393173 430880
대상 8368 24150 34478 35679 39547
현대건설기계 8235 41800 69727 71004 75119
동원F&B 8143 211000 217479 228290 263124
세아베스틸 8105 22600 52335 55309 64892
SNT모티브 7648 52300 57629 58899 62994
현대두산인프라코어 7372 9270 14001 15004 18233
코오롱글로벌 6441 25550 32615 40526 66018
국도화학 6136 68100 110750 140779 237540
한국토지신탁 5971 2365 3994 4164 4712
매일유업 5514 70300 71633 79867 106400
한국자산신탁 5505 4440 7464 8207 10600
한라홀딩스 5299 50600 99092 104989 123987
한진 5142 34400 104108 117894 162315
대한제강 4720 19150 33895 41984 68048
금호건설 4359 11900 19918 24662 39950
태영건설 4337 11150 21827 24885 34736
이수화학 4264 15250 18366 24893 45926
원익머트리얼즈 4028 31950 34042 37365 48069
인탑스 4008 23300 33691 36480 45465
한솔제지 3594 15100 27126 27260 27689
동부건설 3467 15250 26456 29723 40249
화신 3290 9420 9466 10599 14248
코리아써키트 3271 13850 15867 16467 18402
계룡건설 3242 36300 86231 98726 138988
풍산홀딩스 3076 29550 106661 125239 185104
KPX케미칼 2851 58900 115141 116308 120071
랩지노믹스 2782 24300 34235 51552 107351
유니퀘스트 2761 10100 11776 13494 19030
현대코퍼레이션 2527 19100 26986 28623 33899
도이치모터스 2293 7740 11737 12681 15724
한라 2147 5670 12396 14204 20032
금화피에스시 1938 32300 46145 47469 51733
백산 1924 7950 8453 10319 16331
디와이파워 1424 12900 22156 24406 31656
SGC이테크건설 1409 69600 141070 181937 313621
엑시콘 1294 12350 18816 23711 39484
현대코퍼레이션홀딩스 1206 13250 22817 24129 28356
코메론 1122 12400 19743 20388 22466
이노인스트루먼트 856 2125 2280 2418 2862
10월4주차 매수가격 돌파          
에스엘 16510 34250 32996 34396 38907

 

반응형

'주식' 카테고리의 다른 글

[21년 11월 2주차] S-RIM 종목  (0) 2021.11.07
[21년 11월 1주차] S-RIM 종목  (0) 2021.11.01
[21년 10월 4주차] S-RIM 종목  (0) 2021.10.19
[21년 10월 3주차] S-RIM 종목  (0) 2021.10.10
[21년 10월 2주차] S-RIM 종목  (0) 2021.10.02
반응형

싱글턴 패턴은 안티 패턴이라고 주장하는 사람도 많지만 여전히 많은 곳에서 사용되고 있다.

 

싱글턴이란 애플리케이션이 실행 중에 객체를 하나만 가질 수 있는 클래스를 의미한다.

 

싱글턴을 구현하는 방법은 무수히 많으며 이펙티브 자바에서는 세 가지를 설명한다.

 

public static final 변수로 접근 가능한 싱글턴

public class PublicStaticFinalSingleton {
	public static final PublicStaticFinalSingleton INSTANCE = new PublicStaticFinalSingleton();

	private PublicStaticFinalSingleton() {

	}

	public void hello() {
		System.out.println("hello");
	}
}


public class Rule3 {

	public static void main(String[] args) {
		PublicStaticFinalSingleton.INSTANCE.hello();

		new PublicStaticFinalSingleton(); // private 생성자 뿐이므로 컴파일 에러
	}
}

 

getInstance()와 같은 정적 팩토리 메서드로 접근 가능한 싱글턴

public class GetInstanceSingleton {
	private static final GetInstanceSingleton INSTANCE = new GetInstanceSingleton();

	private GetInstanceSingleton() {

	}

	public static GetInstanceSingleton getInstance() {
		return INSTANCE;
	}

	public void hello() {
		System.out.println("hello");
	}
}

public class Rule3 {

	public static void main(String[] args) {
		GetInstanceSingleton.getInstance().hello();

		new GetInstanceSingleton(); // private 생성자 뿐이므로 컴파일 에러
	}
}

 

위 두 방법은 거의 비슷한 방법으로 Eager initialization을 사용한 싱글톤 방식이라고도 한다. 하지만 몇 가지 문제점이 있다.

 

1. 클래스가 로드하게 되면 바로 객체를 생성한다. 만약 해당 싱글톤 클래스가 객체를 생성하는데 많은 시간과 비용이 발생한다면, 애플리케이션이 로드되는데 오래 걸리는 문제가 있을 수 있다. 

 

2. 리플렉션을 사용한다면 생성자가 private여도 호출할 수 있다. 생성자가 두 번 호출되면 예외를 던지도록 처리하여 방어할 수 있다.

 

3. 싱글턴 클래스가 Serializeable이 가능하다면 역직렬화 때마다 새로운 객체가 생성된다. 나중에 포스팅할 내용을 미리 포스팅하여 설명하자면 아래와 같다.

 

/**
 * 싱글턴 클래스는 오직 하나의 객체만 생성되게 하는 클래스이다.
 * 만약 Serializable을 구현한다면 readObject에 의해서 새로운 객체가 만들어지므로 싱글턴 클래스가 아니게 된다.
 *
 * @author gwon
 * @history
 *          2019. 6. 8. initial creation
 */
public class SingletonElvis implements Serializable {
	public static final SingletonElvis INSTANCE = new SingletonElvis();

	private SingletonElvis() {

	}

}

public class Rule77 {

	public static void main(String[] args) throws IOException, ClassNotFoundException {
		// 싱글턴으로 미리 구현된 동일한 객체만 사용 가능
		SingletonElvis elvis = SingletonElvis.INSTANCE;

		// 직렬화 후, 역직렬화
		SingletonElvis newElvis = (SingletonElvis) deserialize(serialize(elvis));

		System.out.println(elvis == newElvis); // false
	}
}

위와 같이 싱글톤을 역직렬 화하면 새로운 객체가 생성되어 객체가 2개 이상이 된다.

 

이를 방어하기 위해서는 아래와 같이 역직렬화 후 호출되는 메서드인 readResolve() 메서드를 항상 동일한 객체를 리턴하도록 작성하면 된다.

/**
 * 이를 막기 위해 readResolve 메서드를 구현하면 싱글턴 속성을 만족하게 오직 하나의 객체만 반환하게 하면 된다.
 *
 * @author gwon
 * @history
 *          2019. 6. 8. initial creation
 */
public class SingletonElvisWithReadResolve implements Serializable {
	public static final SingletonElvisWithReadResolve INSTANCE = new SingletonElvisWithReadResolve();

	private SingletonElvisWithReadResolve() {

	}

	// 역직렬화가 끝난 후, 해당 메서드가 호출되므로 항상 동일한 객체(싱글턴)을 반환하도록 함.
	private Object readResolve() {
		return INSTANCE;
	}

}

 

Enum을 사용한 싱글턴

위에서 언급한 리플렉션, 직렬화를 위한 방어 로직을 작성하기 귀찮다면 Enum을 사용하는 것도 좋은 방법이다.

public enum EnumSingleton {
	INSTANCE;

	public void hello() {
		System.out.println("hello");
	}
}

public class Rule3 {

	public static void main(String[] args) {
		EnumSingleton.INSTANCE.hello();
	}
}

Enum은 직렬화가 자동으로 처리되며, 리플렉션을 통한 공격에도 안전하다.

 

위까지가 이펙티바 자바에서 설명하는 싱글톤 내용이다.

 

Lazy Initialization, Lazy Holder

Eager initialization 싱글톤이 있다면 Lazy initialization 싱글톤도 있다. 소스는 아래와 같다.

public class LazyInitializationSingleton {
	private static LazyInitializationSingleton INSTANCE;

	private LazyInitializationSingleton() {}

	public static LazyInitializationSingleton getInstance() {
		if (INSTANCE == null) {
			INSTANCE = new LazyInitializationSingleton();
		}
		return INSTANCE;
	}

	public void hello() {
		System.out.println("hello");
	}
}

Lazy Initialization은 INSTANCE 필드에 바로 초기화하지 않고 getInstance()를 최초로 호출될 때 객체를 생성하는 방식이다. 따라서 호출되지 않는다면 객체 생성이 미루어지므로 애플리케이션이 로드되는데 부담이 없다.

 

하지만 여러 쓰레드가 동시에 getInstance()를 호출할 경우 객체가 두 번 이상 호출될 수 있는 위험이 존재한다. 이를 방지하기 위해 getInstance()에 synchronized 키워드를 사용하여 해결할 수 있지만, 해당 싱글톤이 자주 사용된다면 효율적이지 않다.

 

따라서 이를 해결하는 방법이 Lazy Holder이다.

 

Lazy Holder는 JVM 클래스 로더의 동작 방식을 이용하여 Lazy Initialization를 만족하면서, 동기화 문제도 해결한다.

https://en.wikipedia.org/wiki/Initialization-on-demand_holder_idiom

public class LazyHolderSingleton {
	private LazyHolderSingleton() {};

	public static LazyHolderSingleton getInstance() {
		return LazyHolder.INSTANCE;
	}

	private static class LazyHolder {
		private static final LazyHolderSingleton INSTANCE = new LazyHolderSingleton();
	}

	public void hello() {
		System.out.println("hello");
	}
}

Lazy Holder의 원리는 다음과 같다.

 

1. LazyHoladerSingleton은 static 필드가 없기 때문에, 즉 초기화할 것이 없으므로 아주 빠르게 클래스가 로드된다.

2. LazyHolder는 LazyHolder가 실행되기 전까지는 로드가 되지 않는다.

3. 어디선가 LazyHoladerSingleton.getInstance()를 호출하면 LazyHolder를 로드를 수행하고 초기화를 진행한다.

4. LazyHolder가 로드되면서 static 필드인 INSTANCE를 초기화할 때는 JVM 원리상 동시에 수행할 수 없다.

5. 따라서 LazyHolder는 멀티스레드에서도 안전하게 LazyHolderSingleton의 생성자를 호출하여 초기화를 완료한다.

반응형
반응형

사경인 회계사님이 쓴 재무제표 모르면 주식투자 절대로 하지마라에 나오는 공식인 S-RIM을 계산하여 해당하는 종목을 매주 제공합니다.

 

재무제표 정보를 제공하는 사이트(http://comp.fnguide.com)를 크롤링하여 필요한 정보를 구했습니다.

 

특히, ROE 같은 경우는  당해에 컨센서스가 추측하는 ROE를 기준으로 하였고, 컨센서스가 존재하지 않을 경우 대상에서 제외합니다.

 

목표 수익률은 9%로 하였습니다.

 

당기순이익이 어떠한 이유로 인해(투자, 매각 등) 너무 높아 ROE가 비정상적으로 다른 해보다 높은 기업이 존재합니다.

따라서 아래 종목 리스트는 투자에 참고만 해주시고, 반드시 해당 기업의 재무제표를 다시 확인해주시기 바랍니다.

 

 

종목명 시가총액 현재가격 매수가격 중간가격 매도가격
NAVER 651304 396500 515344.7907 785284.7909 1655091.458
기아 341316 84200 92275.6582 101280.3881 130295.6289
POSCO 278562 319500 592496.2299 632809.6438 762708.4219
KB금융 232437 55900 110063.0445 111683.8053 116906.257
SK텔레콤 213298 296000 370222.9019 381915.0507 419589.7523
신한지주 203282 39350 90366.81458 91004.0423 93057.3316
LG 150694 95800 148111.2018 161075.7226 202850.2897
하나금융지주 133608 44500 110713.3233 112761.627 119361.7169
HMM 117969 29100 39100.88719 57984.96057 118833.6414
우리금융지주 87367 12000 34448.8811 34962.70268 36618.34999
한화솔루션 83780 43800 45602.64708 48201.85839 56577.09485
롯데케미칼 83289 243000 438419.8966 462375.9546 539567.6969
LG디스플레이 65122 18200 36612.61763 38293.8118 43710.99299
LG유플러스 64400 14750 17649.89598 17872.84832 18591.25033
CJ제일제당 61722 410000 411171.9697 432243.7294 500141.6217
미래에셋증권 55400 8720 16673.08769 17289.3626 19275.13731
금호석유 54690 179500 280369.0153 383882.8147 717427.2795
한국금융지주 48314 86700 159713.1929 194141.0464 305075.2411
DB손해보험 46232 65300 95016.28404 98713.76093 110627.8531
삼성증권 42507 47600 76096.96351 85013.47156 113744.442
GS 42137 45350 105365.937 111582.7729 131614.8
NH투자증권 36724 13050 23867.5798 26175.52619 33612.24236
GS건설 35645 41650 54844.16105 56968.66799 63814.30143
메리츠증권 33473 4910 8226.479685 9021.96353 11585.18925
KCC 33058 372000 609006.0707 614478.4725 632111.7673
포스코인터내셔널 28561 23150 28884.72873 30477.66076 35610.44174
키움증권 28186 107500 206086.3633 249706.5393 390260.4395
대우건설 27514 6620 9124.842647 10506.16332 14957.0855
효성티앤씨 27178 628000 683419.2244 1011230.846 2067512.739
한화 25448 33950 71037.25003 77449.42727 98110.88728
현대해상 25256 28250 51675.32516 51685.54486 51718.47502
효성 22757 108000 146778.2469 171076.5566 249371.1098
JB금융지주 17788 9030 21684.03698 22879.86601 26733.09287
DGB금융지주 17422 10300 31069.15398 31154.86928 31431.063
동국제강 17369 18200 31847.27574 37541.36774 55888.9975
HDC현대산업개발 17202 26100 47490.28821 50363.37456 59621.09728
두산 16293 98600 151557.5948 182579.2034 282537.72
에스엘 15859 32900 32996.06373 34396.2341 38907.89417
DL 14460 69000 302910.0799 385963.0902 653578.3458
SK가스 14215 154000 229509.5573 236216.545 257827.95
대한유화 13488 207500 325188.3841 337150.196 375693.812
LX인터내셔널 11899 30700 50838.3908 59630.07224 87958.82353
유니드 11379 128000 154525.1943 189929.7434 304011.0682
한섬 10517 42700 47998.42973 48531.27487 50248.22033
GS홈쇼핑 10165 154900 198218.4544 205333.0791 228257.981
풍산 10019 35750 62986.06146 68248.09658 85203.54308
대한해운 9384 2940 3482.849862 3586.530053 3920.610671
세아베스틸 9001 25100 52334.77083 55308.91773 64892.27998
동원산업 8514 231500 381471.0946 393173.2068 430880.0125
대상 8368 24150 34478.32288 35678.86056 39547.25975
동원F&B 8104 210000 217479.0141 228289.7826 263124.4811
현대건설기계 7841 39800 69727.17046 71004.09613 75118.6344
SNT모티브 7750 53000 57628.69715 58899.41154 62993.9357
현대두산인프라코어 7372 9270 13059.15418 13385.77486 14438.21925
코오롱글로벌 7009 27800 32471.73227 40280.57973 65442.42155
국도화학 6632 73600 110749.8977 140779.0988 237539.8579
한국토지신탁 5997 2375 3993.909104 4164.08767 4712.440826
한라홀딩스 5550 53000 99092.48058 104988.6593 123987.4574
한국자산신탁 5548 4475 7464.238005 8206.919 10600.0022
매일유업 5514 70300 71633.2132 79867.41276 106399.8336
한진 5247 35100 104107.5764 117893.5977 162315.2219
대한제강 5065 20550 33895.28427 41984.02493 68047.74485
금호건설 4506 12300 19917.95741 24662.38253 39949.9746
태영건설 4473 11500 21827.05341 24884.54941 34736.48098
이수화학 4404 15750 18365.7773 24893.15126 45925.80067
원익머트리얼즈 4198 33300 34042.46455 37364.50207 48068.84518
인탑스 3947 22950 33691.01524 36479.61506 45465.10336
한솔제지 3570 15000 27126.32119 27259.55699 27688.87237
계룡건설 3434 38450 86230.52816 98725.74798 138988.1229
동부건설 3421 15050 26456.22618 29722.91079 40248.89451
코리아써키트 3260 13800 15866.64492 16467.21117 18402.36908
풍산홀딩스 3175 30500 106660.7121 125239.3111 185103.6858
KPX케미칼 2875 59400 115140.7125 116308.3863 120070.8907
랩지노믹스 2771 24200 34235.43351 51552.22243 107350.7645
유니퀘스트 2761 10100 11775.79456 13494.00868 19030.47637
현대코퍼레이션 2375 17950 26986.29867 28623.4011 33898.50894
도이치모터스 2257 7620 11737.31093 12681.45358 15723.69102
한라 2207 5830 12395.77145 14204.44681 20032.40074
백산 2001 8270 8453.22542 10319.1231 16331.46006
금화피에스시 1947 32450 46145.32414 47468.61579 51732.55556
디와이파워 1480 13400 22156.24237 24406.12115 31655.73056
SGC이테크건설 1417 70000 141069.9318 181937.2469 313620.818
엑시콘 1325 12650 18815.54523 23710.77946 39484.31197
현대코퍼레이션홀딩스 1174 12900 22816.57762 24128.51789 28355.88096
코메론 1086 12000 19743.25437 20388.15499 22466.16809
이노인스트루먼트 866 2150 2280.079941 2418.021125 2862.498273
영원무역          
SK디앤디          
웅진씽크빅          
화신          
한세예스24홀딩스          
하이비젼시스템          
제우스          
반응형

'주식' 카테고리의 다른 글

[21년 11월 2주차] S-RIM 종목  (0) 2021.11.07
[21년 11월 1주차] S-RIM 종목  (0) 2021.11.01
[21년 10월 5주차] S-RIM 종목  (0) 2021.10.24
[21년 10월 3주차] S-RIM 종목  (0) 2021.10.10
[21년 10월 2주차] S-RIM 종목  (0) 2021.10.02
반응형

규칙 1에서는 생성자 대신 정적 팩토리 메서드를 사용을 고려해보자는 규칙이었다.

 

하지만 생성자 뿐만아니라 정적 팩토리 메서드의 인자가 많을 때는 어떤 위치에 어떤 값이 들어가야 하는지 클라이언트가 하나씩 확인하면서 값을 채워줘야 하기 때문에 사용하기 불편한다.

 

따라서 이를 개선하고자 점진적 생성자 패턴(telescoping constructor pattern)이 만들어졌다.

 

점진적 생성자 패턴

점진적 생성자 패턴이란 필수 인자를 받는 생성자를 하나 정의하고, 선택적 인자를 받는 생성자를 여러개 점진적으로 만드는 방식이다.

 

아래는 Netty의 io.netty.handler.proxy.HttpProxyHandler 예시이다.

public final class HttpProxyHandler extends ProxyHandler {


    private final HttpClientCodecWrapper codecWrapper = new HttpClientCodecWrapper();
    private final String username;
    private final String password;
    private final CharSequence authorization;
    private final HttpHeaders outboundHeaders;
    private final boolean ignoreDefaultPortsInConnectHostHeader;
    private HttpResponseStatus status;
    private HttpHeaders inboundHeaders;

    public HttpProxyHandler(SocketAddress proxyAddress) {
        this(proxyAddress, null);
    }

    public HttpProxyHandler(SocketAddress proxyAddress, HttpHeaders headers) {
        this(proxyAddress, headers, false);
    }

    public HttpProxyHandler(SocketAddress proxyAddress,
                            HttpHeaders headers,
                            boolean ignoreDefaultPortsInConnectHostHeader) {
		...
    }

    public HttpProxyHandler(SocketAddress proxyAddress, String username, String password) {
        this(proxyAddress, username, password, null);
    }

    public HttpProxyHandler(SocketAddress proxyAddress, String username, String password,
                            HttpHeaders headers) {
        this(proxyAddress, username, password, headers, false);
    }

    public HttpProxyHandler(SocketAddress proxyAddress,
                            String username,
                            String password,
                            HttpHeaders headers,
                            boolean ignoreDefaultPortsInConnectHostHeader) {
  		...
    }

 

아래와 같이 생성자가 필요한 인자에 따라서 여러개가 존재하기 때문에 많은 인자가 들어있는 하나의 생성자보다는 사용하기가 편한다.

하지만 만약 해당 클래스의 필드가 추가되게 되면, 생성자를 추가로 생성해야 한다는 문제가 있다.

옵셔널 한 필드라면 생성자가 하나만 추가하게 코드를 작성할 수 있지만, 필수로 입력해야 하는 필드라면 여태 만들어 둔 생성자에 모두 추가해야 하므로 고쳐야 하는 부분이 더욱 많아진다.

 

필드 개수에 따라서 생성자를 추가하는 방법이 아닌 다른 방법은 없을까? 다음 대안인 자바빈 패턴(JavaBeans) 패턴을 보자.

 

자바 빈 패턴

자바 빈 패턴은 한국에서 제일 많이 사용하는 패턴이 아닐까 싶다.

 

자바 빈 패턴은 디폴트 생성자로 객체를 만들고 필드의 setter 메서드로 필요한 값을 하나씩 호출하여 채우는 방식이다.

public class User {
	private String name;
	private int age;
	private String addr;

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public void setAge(int age) {
		this.age = age;
	}

	public void setAddr(String addr) {
		this.addr = addr;
	}
}

public static void main(String[] args) {
	User user = new User();
	user.setName("홍길동");
	user.setAge(10);
	user.setAddr("서울");
}

 

점층적 생성자 패턴보다 복잡하지 않기 때문에 생성하기도 쉬우며, 코드 읽기에도 어려움이 없다.

 

하지만 자바 빈 패턴은 요즘(?) 대세인 클래스 생성 규칙을 위반한다.

 

다른 객체 생성 방식과는 다르게 한 번의 함수 호출로 객체 생성을 끝낼 수 없기 때문에 객체의 일관성이 깨질 수 있다.

하나의 함수로 객체를 생성하게 된다면, 해당 객체의 필드에 값들이 유효한지를 보장하도록 코드를 작성할 수 있지만 각각 필드에 대한 setter에서는 그 유효성을 보장하도록 코드를 작성하기 어렵고, 그렇게 한다고 하더라도 잘못 코드를 작성할 경우, 버그를 디버깅하기 어렵다.

 

또한 setter가 존재한다는 것은 값을 변경할 수 있기 때문에 Immutable 클래스를 만들 수가 없다.

 

인자가 많은 생성자, 점진적 생성자 패턴, 그리고 자바 빈 패턴을 단점을 커버할 객체 생성 방법은 없을까? 그 대안이 바로 빌더 패턴(Builder Pattern)이다.

 

빌더 패턴

빌더 패턴은 GOF 디자인 패턴 중에 하나이다. 하지만 여기서 설명하는 빌더 패턴은 GOF에서 설명하는 빌더 패턴을 객체 생성 관점에서 변형에서 사용한 예라고 할 수 있다.

 

빌더 패턴은 객체를 생성할 클래스안에 빌더 클래스를 작성하고, 이 빌더 클래스를 이용하여 객체를 생성한다.

일반적인 빌더 패턴 만드는 순서는 다음과 같다.

 

1. 필수로 입력받아야하는 필드만을 가진 생성자를 작성한다.

2. 옵셔널로 입력받아야하는 필드는 setter로 만들고 추가적으로 자신을 리턴하도록 한다.

3. build() 메서드를 만들고 실제 객체 생성자에 자신을 넘겨 해당 객체를 리턴한다.

NutritionFacts cocaCola = new NutriFacts.Builder(240, 8)
      .calories(100).sodium(35).carbohydrate(30).build();
public class NutritionFacts {
	private final int servingSize;
	private final int servings;
	private final int calories;
	private final int fat;
	private final int sodium;
	private final int carbohydrate;

	private NutritionFacts(Builder builder) {
		servingSize = builder.servingSize;
		servings = builder.servings;
		calories = builder.calories;
		fat = builder.fat;
		sodium = builder.sodium;
		carbohydrate = builder.carbohydrate;
	}

	public static class Builder {
		private final int servingSize;
		private final int servings;

		private int calories = 0;
		private int fat = 0;
		private int sodium = 0;
		private int carbohydrate = 0;

		public Builder(int servingSize, int servings) {
			this.servingSize = servingSize;
			this.servings = servings;
		}

		public Builder calories(int val) {
			calories = val;
			return this;
		}

		public Builder fat(int val) {
			fat = val;
			return this;
		}

		public Builder sodium(int val) {
			sodium = val;
			return this;
		}

		public Builder carbohydrate(int val) {
			carbohydrate = val;
			return this;
		}

		public NutritionFacts build() {
			return new NutritionFacts(this);
		}
	}
}

 

빌더 패턴은 위에 다른 패턴의 단점을 해결하면서 여러 장점이 존재한다.

 

1. 빌더 패턴은 build() 메서드에서 한 번에 객체를 생성하기 때문에 필드의 유효성을 판단할 수 있다.

 

2. build()로 만들어진 객체 자체에 setter을 두지 않도록 하여 Immutable 하게 객체를 생성할 수 있다.

 

3. 빌더 객체는 재사용할 수 있다.

NutriFacts.Builder builder = new NutriFacts.Builder(240, 8)
      .calories(100).sodium(35).carbohydrate(30);
      
NutriFacts n1 = builder.build();

builder.sodium(0);
NutriFacts n2 = builder.build();

 

4. 빌더에 부가적인 기능을 추가 할 수 있다.

public class NutritionFacts {
    ...

	public static class Builder {
    	private static int count = 0;
        
        ...

		public NutritionFacts build() {
			count++;
			return new NutritionFacts(this);
		}
        
	}
}

 

단점으로는 코드의 양이 증가할 수 있으며, 다른 패턴보다는 성능이 약간 떨어진다.

 

하지만 요즘 여러 라이브러리에서 어노테이션만으로 빌더 패턴을 적용할 수 있도록 제공하고 있기 때문에 첫 번째 단점은 쉽게 해결할 수 있다. (lombok 등)

@Builder
public class Member {...}
반응형

+ Recent posts