OOP는 속성 개념을 포함하도록 어떻게 발전 했습니까?


12

나는 C ++ 배경에서 왔으며 현재 직장에서 C #을 외출 중이며 공개 필드와 속성의 차이점 과이의 변형과 화신의 앞뒤로 많은 Q & A를 읽었습니다. 기본 질문 (예 :이 SO 게시물 및 모든 관련 링크 된 질문 ). 이러한 모든 질문은 속성 시스템의 존재를 당연히 받아들이는 실질적인 차이 측면에서 다루어졌지만, 처음에는 속성을 지원하기로 결정한 모든 언어의 디자이너가 어떤 점 에서이 주제에 접근하는 것이 좋을 것이라고 생각합니다 장소가 생각 중입니다 (Wikipedia 기사의 목록을 확인 하십시오.). OOP가 C ++ / Java에서 어떻게 진화하여 Wikipedia 기사가 메소드와 멤버 데이터 사이의 중간 위치로 흥미롭게 식별되는 내용으로 확장 되었습니까?

"즉, 속성은 클래스의 멤버 코드 (메서드)와 멤버 데이터 (인스턴스 변수) 사이에 있으며 속성은 공용 필드보다 더 높은 수준의 캡슐화를 제공합니다."

MSDN은 추가 배경을 추가합니다.

"속성은 기술적으로 기술과 매우 유사하지만 사용 시나리오 측면에서 상당히 다릅니다. 스마트 필드로 간주해야합니다. 필드의 호출 구문과 방법의 유연성이 있습니다."

이 중간 수준의 캡슐화가 일반적으로 프로그래밍에 유용하다는 것이 어떻게 나타 났는지 알고 싶습니다. 나는이 개념이 OOP 패러다임을 표현한 프로그래밍 언어의 첫 번째 화신에 존재하지 않았다고 가정합니다.


8
베어 언어 기능은 getter 및 setter 메소드에 편리한 구문 설탕입니다. 해석과 용어 뒤에 더 깊은 이유가 있는지는 모르겠습니다.

OO 전문가 라운드에서 질문 제목이 도발 될 수 있으며 실제로 요청한 내용을 방해 할 수 있습니다. 나는 자신을 OO 전문가로 삼는 것이 아니라 몇 년 동안 "OO 사용자"일뿐입니다.
Doc Brown

파이썬의 '매개 변수없는 메소드'에서 C ++로가는 것을 놓친 구문상의 장점입니다. IMO BMI = bob.weight/sq(bob.height)없이 더 잘 읽습니다 ().
OJFord

Active X (COM) 개체를 구성하는 방법으로 속성이 원래 (.net이 아닌) Visual Basic에 있다고 생각합니다. 이 도구의 속성 표는 언어로 속성을 채택하는 것과 관련이있을 수 있습니다. 원래 Visual Basic은 여러 가지 방법으로 객체 지향적이지 않지만 클래스와 같은 것을 만드는 기능이있었습니다.
Frank Hileman

계속 : 속성 창은 코드를 작성하지 않고 개체를 구성하는 방법이었습니다. RAD 개발이라고 불렀습니다. 이 링크는 VB6 속성 창의 스크린 샷을 포함 microsoft.com/mspress/books/WW/sampchap/4068.aspx
프랭크 Hileman에게

답변:


5

캡슐화와 통일 접근 원칙에 관한 것입니다.

개체는 기존 데이터를 반환하거나 메서드를 실행하여 메시지에 응답 할 수 있어야하지만 보낸 사람은 어떤 메시지인지 알 수 없어야합니다. 또는 발신자 측에서이 정보를 보는 경우 : 발신자가 기존 데이터에 액세스하거나 균일 한 인터페이스를 통해 메소드를 실행할 수 있어야합니다.

이를 달성하는 몇 가지 방법이 있습니다.

  • 데이터를 완전히 제거하고 메소드를 사용하십시오 (Newspeak가 수행)

    • 위의 덜 급진적 인 형태 : 공개 인터페이스에서 데이터 제거 하십시오 . 즉 , 공개 인터페이스 에서 데이터를 항상 비공개로 설정하십시오.
  • 메소드를 완전히 제거하고 데이터를 가져 오십시오 (자체가이를 수행하는 경우 "메소드"는 Method인스턴스 변수에 지정된 오브젝트이며 인스턴스 변수는 가상 디스패치로 조회 됨)

  • 방법 및 데이터 (스칼라이이 필드를 액세스하는 인수 목록 (않고 메소드를 호출 구문 구별하지 사이 구문 또는 의미 구별을하지 foo.bar필드에 할당하는) 특수라는 메소드 (호출하는 구문 구별 foo.bar = baz) 같다 로 foo.bar_=(baz)즉 방법라는 통화 foo_=및 읽기 전용 값은 무시 될 또는 파라미터리스트 (즉없는 방법으로 구현할 수 val foo대체 될 수있는 수퍼 클래스) (또는이 abstract val방법으로 서브 클래스에 구현 될) def foo)

그러나 Java는 Uniform Access Principle을 따르지 않습니다. Java에서는 데이터 액세스와 메소드 실행을 구별 할 수 있습니다. foo.bar와 다릅니다 foo.bar(). 그 이유는 필드와 방법이 의미 적으로 구문 적으로 구별되기 때문입니다.

C #은 언어에 속성, 기본적으로 필드처럼 보이는 메서드를 추가하여이 문제를 해결하려고합니다. 그러나 메서드 호출은 여전히 ​​필드 및 속성 액세스와 모양과 느낌이 다릅니다. 필드와 속성에는 이제 균일 액세스가 있지만 메서드에는 여전히 없습니다.

따라서 이것은 실제로 문제를 해결하는 것은 아닙니다. 사물에 액세스하는 세 번째 방법을 추가하여 사물에 액세스하는 두 가지 다른 방법으로 수정할 수는 없습니다! 세 번째 방법이 다른 두 가지 방법 중 하나처럼 보이지만 (적어도) 두 가지 다른 방법이 있습니다. 하나를 제외한 다른 모든 방법을 제거하거나 차이점을 제거하여 문제를 해결할 수 있습니다.

메서드, 속성 및 필드가 포함 된 언어를 사용하는 것은 좋지만 세 가지 모두 균일 한 액세스 권한을 가져야합니다.


1
왜 당신과 다른 사람들은 Uniform Access를 유지하는 것이 그렇게 중요하다고 생각합니까? 메소드를 사용하면 수행하거나 수행하는 작업을 변경하기위한 매개 변수를 제공 할 수 있습니다. 필드 또는 속성을 사용하면이 기능이 없으므로 일반적으로 데이터 만 반환합니다 (속성은 개인 필드를 노출하는 대신 메서드를 실행하여 구현할 수 있음). 그것은 내가 익숙해 져서 직관적 인 것처럼 보이지만 균일 한 액세스를 통해 우아함이나 생산성에서 무엇을 얻을 수 있습니까? 클래스 외부에서 구현 세부 정보가 유출되는 것을 두려워합니까?
Mike는 Monica를 지원합니다.

1
UAP는 공용 인터페이스를 중단하지 않고 구현 세부 사항을 자유롭게 변경할 수있는 권한을 보유합니다. 일반적인 예는 로깅을 추가하는 것입니다. 메서드를 통해 액세스를 제공하면 메서드의 내부를 사소하게 변경하여 로그에 쓸 수 있습니다. 공개 필드를 사용하면 먼저 모든 클라이언트 코드를 손상시키는 메소드로 변환하지 않고 로깅을 추가 할 수 없습니다. 주요 변경 사항을 위험에 빠뜨릴 수없는 경우 방법을 사용해야합니다. 속성은 완전한 방법이지만 필드처럼 보이기 때문에 최적의 절충안입니다. UAP를 준수하면 캡슐화가 향상되고 긴밀한 결합이 줄어 듭니다.
amon

이 질문에 대한 좋은 대답이 많이 있지만 프로그래밍 언어의 본질에 대한 더 근본적인 측면을 끌어 내고 UAP의 관련 공식 개념을 정교화 하여이 문제를 해결했다고 생각합니다. 솔리드
jxramos

18

글쎄, 100 % 확신 할 수는 없지만, 예상보다 훨씬 간단한 것 같습니다. 90 년대의 OO 모델링 스쿨에서, 캡슐화 된 멤버 속성을 가진 클래스 모델링이 요구되었으며, C ++ 또는 Java와 같은 언어로 구현 될 때, 이는 일반적으로 많은 게터와 세터가있는 코드로 이어 지므로 많은 "잡음" 비교적 간단한 요구 사항에 대한 코드. 링크 된 Wikipedia 기사에 나열된 언어의 대부분 (아마도 모두 이것을 확인하지는 않았 음)은 90 년대 후반에 객체의 "속성"을 도입하기 시작했습니다.

언어 디자이너들이 그 소음을 줄이기 위해 약간의 구문 설탕을 추가하기로 결정한 주된 이유라고 생각합니다. 특성이 더 확실히 "핵심 OO 개념"비록, 그들은 적어도이없는 것을 객체 지향 함께 할 수 있습니다. 그들은 "OOP의 진화"를 보여주지 않지만 (질문 제목에서 가정 한 것처럼) 구현을 쉽게하기 위해 프로그래밍 언어 수준에서 OO 모델링 을 지원 합니다.


속성은 필드의 추상화이며 필드는 객체 지향 프로그래밍의 일부라는 점을 제외하고는 객체 지향 프로그래밍과 관련이 없습니다. 그러나 올바르게 지적했듯이 객체 지향 프로그래밍에는 속성이 필요하지 않습니다.
Frank Hileman

2
@FrankHileman : "속성은 필드의 추상화이며 필드는 객체 지향 프로그래밍의 일부입니다"-컨셉 실제로 OOP와 관련이 있다는 것에 동의하는 것처럼 들립니다 . 그게 당신이 저를 공감 한 이유입니까?
Doc Brown

3
lol. 그를 비난 할 수 있습니까? 그는 화장실에서 미끄러 져 싱크대에서 머리를 쳤다. 어쨌든 ... 내가 항상 본 방식은 속성 엄격하게 OO에 있지 않다는 것입니다. 캡슐화에 도움이되고 캡슐화는 OO에 도움이됩니다.
MetaFight

1
하아! 이것은 프로그래머에 대한 소개입니다. Lol, 평범한 ol stackoverflow에서 내 동등한 경험보다 훨씬 더 가열 :-p 하루를 섞는 좋은 방법!
jxramos


11

당신은 그것을 거꾸로 가지고 있습니다. 람다 미적분학 은 프로그래밍 언어의 핵심 형식 기반으로 존재하며 수십 년 동안 사용되었습니다. 필드가 없습니다.

변경 가능한 상태를 모델링하려면 두 가지 추상화를 만들어야합니다. 하나는 어떤 상태를 설정하고 다른 하나는 그 상태를 검색하는 것을 나타냅니다 ( 참조 로 내 TaPL 버전 13 장 ). 익숙한 소리? A로부터 이론적 배경, OO는이 물건을 가지고 진화하지 않았다. OO는 프로그래밍 언어 101을 읽고 앞으로 나아갔습니다.

A로부터 실제적인 관점이 매우 분명한 동기가있다. 당신은 C ++ 배경에서 왔으므로 공개 입력란이 있으면 어떻게해야합니까? "이 텍스트 상자가 변경 될 때마다 번거 롭도록"디자인을 변경하려고 할 때 어떻게됩니까? 개발자가 "UpdateTextbox"를 스스로 호출하도록 신뢰할 수 없기 때문에 해당 필드를 강제 종료하고, 기능을 수행하고, 해당 논리를 연결해야합니다. 이것은이다 아주 (불행히도 아직 및 속성의 .NET 구현의 주요 변경) 당신의 API에 대한 주요 변경. 행동의이 종류는 사방에 윈도우 API한다. C #은 Microsoft에서 큰 문제가 되었기 때문에 C #에서이를 덜 고통스럽게 만들고 싶었습니다.

다른 큰 동기는 Java Beans 와 그 친족입니다. 프레임 워크의 번호를 찾기 위해 자바 반사를 사용하여 만들어진 GetXSetX쌍 효과적으로 현대적인 속성처럼 취급합니다. 그러나 실제 언어 구성이 아니기 때문에 이러한 프레임 워크는 깨지기 쉬우 며 부자연 스럽습니다. 이름을 잘못 입력하면 상황이 자동으로 중단됩니다. 하나가 리팩토링되면 아무 것도 부동산의 다른쪽으로 이동하지 않습니다. 그리고 모든 필드 / get / set 상용구를 수행하는 것은 장황하고 지루합니다 (Java의 경우에도!). C #은 주로 "학습이있는 Java"로 개발 되었기 때문에 그러한 종류의 고통이 그러한 교훈 중 하나였습니다.

그러나 가장 큰 것은 재산 개념이 성공적이라는 것입니다. 이해하기 쉽고 사용하기 쉽습니다. 이것들은 채택을 크게 도와 주며, 도구 로서 프로그래머는 속성이 기능이나 필드보다 문제의 하위 집합을 더 깨끗하게 해결한다는 것을 발견했습니다.


7
나는 당신에게 무관 한 형식적인 쓰레기에 대해 너무 많은 언급을하여 당신을 하향 표명했습니다. 프로그래밍 언어의 실제 구현은 모델이 람다 미적분에 포함되었는지 여부보다 고려해야 할 사항이 훨씬 더 심각합니다.
DeadMG

9
@DeadMG-그것은 사실이지만, 프로그래밍 언어 구현 자들은 그 와 관련없는 공식적인 쓰레기에 항상 익숙 할 것이다 . 그것이 그들의 디자인에 영향을 미치지 않았다고 생각하는 것은 순진합니다.
Telastyn

3
이것은 분명히 "관련없는 공식적인 쓰레기"가 아닙니다. 그러나 람다 미적분학은 초기 프로그래밍 언어에는별로 고려되지 않았을 수 있습니다. 그렇다면 CPU는 아마도 그 사고 방식을 향한 방향 일 것입니다.
Frank Hileman 2014

3
@FrankHileman-나는 Lisp가 그것을 고려했다고 확신한다 ...
Telastyn

4
@Telastyn-그렇습니다. Lisp는 원래 프로그래밍 언어가 아니 었습니다. 기억하십니까?
Frank Hileman 2014

3

.net에서 속성은 예전의 Visual Basic 시절부터 시작되었으며 오늘날의 생각 방식에서는 객체 지향적이지 않았습니다. 그것은 코드로뿐만 아니라 그래픽 편집기에서도 액세스 할 수있는 속성을 노출시키는 구성 요소 측면에서 클래스로뿐만 아니라 모든 것을 표면적으로 처리 한 새로운 COM 시스템을 중심으로 구축되었습니다. VB와 새로 생성 된 C #이 .net에 병합되면 VB는 많은 OOP 기능을 얻었으며 제거하면 거꾸로 될 것이기 때문에 속성을 유지했습니다. Visual Studio에 자동 코드 업데이트 도구가 있다고 생각 모든 속성을 getter 및 setter로 바꾸고 모든 COM 라이브러리와의 호환성을 깨뜨리고있었습니다. 그것들을 모두 지원하는 것은 논리적 일뿐입니다.


델파이에서 온 C #의 조상과 그 이전부터 Object Pascal과 Turbo Pascal with Objects를 무시해서는 안된다고 생각합니다. 이것들은 객체 지향적이며 속성을 가졌습니다. (OP가 TP5.5의 속성을 가지고 있는지 또는 추가되었는지를 기억할 수는 없지만 아마도 Anders에 의해 C #으로 계속 이어
졌을

이 질문에 대한 구성 요소 측면을 강타한 유일한 사람이라는 사실이 매우 흥미 롭습니다. 방금 C #이 만족하는 속성 방법 이벤트 모델의 일부로 속성을 나열한 사이트로 연결되는 질문에 의견을 추가했습니다. 그런 다음 몇 가지 잘못된 긍정을 나타내는 "구성 요소"에 대해 내 질문의 페이지를 다시 검색했지만 귀하의 답변은 실제로 연결된 것과 겹칩니다.
jxramos

3

속성은 구문 설탕 일 뿐이므로 속성은 객체 지향 프로그래밍과 관련이 없습니다. 속성은 피상적으로 필드처럼 보이며 .net 세계에서는 어떤 방식 으로든 필드처럼 동작하는 것이 좋지만 어떤 의미에서도 필드는 아닙니다. 속성은 하나 또는 두 가지 방법에 대한 구문 설탕입니다. 하나는 값을 얻고 다른 하나는 값을 설정합니다. set 메소드 또는 get 메소드는 생략 할 수 있지만 둘다는 아닙니다. get 메소드가 리턴 한 값을 저장하는 필드가 없을 수 있습니다. 필드와 구문을 공유하고 필드를 자주 사용하기 때문에 속성을 필드와 연결합니다.

속성은 필드보다 장점이 있습니다.

  • 속성 세트 방법에서, 속성 값이 저장되기 전에, 새로운 값 또는 객체의 상태가 일련의 전제 조건 또는 불변에 대해 검사 될 수있다.
  • 속성 값의 검색이 논리적으로 필드 값의 검색과 동등한 것으로 간주 될 수있는 경우, 편의를 위해 속성 획득 방법이 존재할 수있다.
  • 속성 세트 방법은 부모 객체에게 또는 객체들에게 속성 값의 변경을 통지하는 것과 같은 다른 동작들을 수행 할 수있다.

속성은 필드의 추상화이며 구문상의 편의를 위해 C #과 같은 언어는 속성에 필드 구문을 채택했습니다.


2
Wikipedia 기사의 첫 번째 줄. "일부 객체 지향 프로그래밍 언어에서 속성은 특별한 종류의 클래스 멤버입니다." 첫 문장은 틀 렸습니다. 그리고 나머지 부분은 질문에 대답하지 않습니다.
Doc Brown

1
@DocBrown : 흥미로운 답변. 많은 Wikipedia 기사가 명확하지 않습니다. 이 기사의 저자를 변호한다고 가정합니까?
Frank Hileman

1
객체 지향 프로그래밍 언어의 모든 기능이 객체 지향 개념과 관련된 것은 아닙니다.
Frank Hileman

1
그것은 당신이 질문에 대답하지 않는다는 사실을 바꾸지 않습니다.
Doc Brown

3
선택적인 세터 만이 아니라는 점에 유의해야합니다. 세터 전용 특성을 가질 수 있습니다.
Telastyn

2

구현함축 의 문제입니다 . C ++ 또는 Java가 씬에 도달하기 전에 속성이 OOP에있었습니다 (시뮬 라에서 가장자리가 거칠고 스몰 토크의 기본입니다). 속성이있는 엔터티는 코드가 첨부 된 값과 개념적으로 다릅니다. 일부 언어 규칙에서 get & set 접두사는 물을 흐릿하게 만드는 역할 만합니다. 언어와 관용적 인 방식으로 필드를 가져 오거나 설정하지 않고 필드에 직접 액세스 할 수 있다고 가정하면 필드와 속성의 차이점을 알 수 있습니다.

OOP의 요점은 사물을 코드가 혼합 된 구조체가 아니라 "실제"세계의 실체로 취급하는 것입니다. 다른 프로그래머는 내가 구현 한 방식에 대해 아주 조금만 알아야합니다. 그들이 가져 오거나 설정할 수있는 다양한 값들 중 어느 것이 실제이고 어떤 값인지에 대해 전혀 염려하지 않아야합니다. 내 벡터를 가로 지르면 각도와 크기를 저장하는지 또는 벡터 객체 내부의 실제 및 가상 구성 요소를 저장할지 알 필요가 없습니다. 내 라이브러리의 V2.0에서 표현을 변경하면 코드에 전혀 영향을 미치지 않아야합니다 (멋진 새 기능을 활용하고 싶을 수도 있습니다). 마찬가지로 엔터티 외부의 데이터에 의존하는 엔터티가 가질 수있는 속성이 있습니다. 그러나 이것은 어휘 관점에서 의심의 여지가없는 속성입니다. 해당 "개체"에 대해 사용할 수있는 데이터가 생년월일 (개인 불변의 멤버) 및 오늘의 날짜라는 것을 알고 있지만 "나이를 공개 할 계산을 수행하십시오"가 아니라 "나이는 몇 살입니까?" 날짜 (표준 시간대, 일광 절약 시간 및 국제 날짜 표시 줄에 따라 자동 증가하는 공용 환경 속성). 나이는 방법이 아니라 속성입니다. 비록 거기에 도달하기 위해서는 약간의 계산이 필요하고 (인공적으로 제한된 수명을 가진 장난감 컴퓨터 표현을 제외하고) 필드로 저장할 수 없습니다. 해당 "개체"에 사용할 수있는 데이터는 생년월일 (개인 불변 구성원)과 오늘 날짜 (공개, 자동 증가 환경 재산, 시간대, 일광 절약 시간 및 국제 날짜 표시 줄에 따라 다름)임을 알고 있습니다 ). 나이는 방법이 아니라 속성입니다. 비록 거기에 도달하기 위해서는 약간의 계산이 필요하고 (인공적으로 제한된 수명을 가진 장난감 컴퓨터 표현을 제외하고) 필드로 저장할 수 없습니다. 해당 "개체"에 사용할 수있는 데이터는 생년월일 (개인 불변 구성원)과 오늘 날짜 (공개, 자동 증가 환경 재산, 시간대, 일광 절약 시간 및 국제 날짜 표시 줄에 따라 다름)임을 알고 있습니다 ). 나이는 방법이 아니라 속성입니다. 비록 거기에 도달하기 위해서는 약간의 계산이 필요하고 (인공적으로 제한된 수명을 가진 장난감 컴퓨터 표현을 제외하고) 필드로 저장할 수 없습니다.

속성을 필드와 메소드의 자식으로 생각하기보다는 메소드가 특정 유형의 속성 인 엔티티에 비해 훨씬 더 만족 스럽습니다. 그렇지 않으면 개념적으로 객체 / 엔터티를 다루지 않고 코드가 첨부 된 데이터 수집을 다루는 것입니다. implementaions는 동일 할 수 있지만, 의미는 다르다.

그러나이 추상화는 비용이 든다는 것은 말할 필요도 없습니다. 클래스를 사용하는 프로그래머가 데이터를 저장하거나 계산해야 할 값을 가져 오거나 설정할 때 데이터에 액세스하고 있는지 알 수없는 경우 언어도 확실하지 않은 수준이있을 수 있습니다 (따라서 접근 자 / 선택자와 값 사이에 중간 코드가 필요합니다). "코드가 포함 된 구조체"에는 개념적으로 잘못된 것이 없습니다. 확실히 훨씬 더 효율적일 수 있습니다. 그러나 모든 곳에서 구현이 누출되기 때문에 OOP가 제거해야하는 것 중 하나입니다.


일부 요점에 동의하고 다른 의견에 동의하지 않지만 전체 메시지는 좋은 것입니다. 객체에 대한 일부 정보는 계산해야하지만 기술적 으로 수행 할 수있는 조치 아닌 기술적 인 정보입니다 .
Pharap

0

전혀 아무것도 없습니다. 속성과 OOP는 서로 관련이 없습니다. 속성은 함수 호출에 대한 구문 설탕에 지나지 않으므로 함수 호출과 정확히 동일한 OOP 연결을 갖습니다.

그건 그렇고, 위키피디아는 완전히 틀 렸습니다. Java에서 볼 수있는 getMember / setMember 패턴은 C #의 특성과 정확히 동일한 장점 (및 단점)을 제공합니다. 원하는 경우 C에서도이 패턴을 복제 할 수 있습니다.

C #의 속성은 언어 지원 구문 설탕에 지나지 않습니다.


3
클래스 또는 객체 컨텍스트 외부의 프로그래밍 언어에서 속성 개념을 본 적이 있습니까? 나는하지 않았다.
Doc Brown

1
@DocBrown : 구현했습니다. 사실, 속성은 일반 함수 호출에 대한 개선이 낮기 때문에 언어 작성자에게 매우 가치가 낮은 대상입니다.
DeadMG

1
OP는 대중적인 프로그래밍 언어의 개념으로서 속성 의 역사 에 대해 묻고있었습니다 . 실제로 역사적 의미에서 속성과 OOP 사이에는 연결이 있습니다.
Doc Brown

2
어쩌면 나는이 속성 개념을 OOP 패러다임 그 자체로 언급하기 위해 약간의 발진이 있었지만 개념으로서 개별 언어와 그 특징을 확실히 능가합니다. 어쩌면 나는 둘 사이의 적절한 온톨로지를 표현하기 위해 고심하고 있습니다. 나는 질문의 제목을 통해 속성이 OOP 형식을 만들거나 깨는 OOP 의 기본 기능 / 개념이라는 것을 제안하지는 않지만 이 OOP 공간에서만 현실을 가지고 있다고 생각합니다. .
jxramos

4
그것들은 C #에서 구문 설탕이 아니라 어셈블리 메타 데이터에 별개의 멤버로 존재하며 데이터 바인딩과 같은 필드로는 할 수없는 속성으로 작업을 수행 할 수 있습니다.
Andy
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.