: 컴퓨터 프로그램을 여러 명령어의 목록으로 보지 않고 여러 개의 독립된 객체들의 집합으로 파악하는 프로그래밍 기법.
I. 객체, 클래스, 인스턴스
A. 객체 (object)
: 객체 지향 프로그래밍(OOP) 에서 클래스(class)가 실제로 구현된 인스턴스(instance)
혹은 클래스(class)에서 구현하기 위한 추상적인 개념
: 프로그램에서 사용되는 데이터 혹은 식별자에 의해 참조되는 공간
ex) 고양이라는 개념
B. 클래스 (class)
: 객체 지향 프로그래밍(OOP)에서 특정 객체를 생성하기 위해 변수와 메소드를 정의하는 템플릿
: 클래스에서는 해당 객체의 속성(state)는 변수(variable)로, 기능(behavior)은 메서드(method)로 정의함.
ex) 고양이라는 객체를 프로그램상 나타내기 위해 변수와 메서드를 정의
internal class Cat
{
// 속성 정의
public string catName; // 이름은 뭔지
public string catSpecies; // 묘종은 뭔지..
public string color; // 색은 뭔지..
public int catAge; // 나이는 몇 살인지..
// 기능 정의
public void meow() // 야옹하고 울기
{
Console.WriteLine("Meow!");
}
public void moving()
{
Console.WriteLine(catName + " is moving..."); // 이동하기
}
public void jump()
{
Console.WriteLine("...Jump!"); // 점프하기
}
}
C. 인스턴스 (instance)
: 객체 지향 프로그래밍(OOP)에서 클래스에 소속된 개별적인 객체.
: 정의된 클래스에 객체를 생성한 경우, 그 객체는 해당 클래스의 인스턴스가 된다.
: 하나의 클래스를 사용하여 유사한 성질을 가진 수많은 인스턴스를 생성할 수 있다.
ex) 고양이 "냬옹스(Nyeaons)"는 Cat 클래스의 인스턴스
Nyeaons
internal class Program
{
static void Main(string[] args)
{
Cat Nyeaons = new Cat();
Nyeaons.catName = "Nyeaons"; // 고양이의 이름은 냬옹스다.
Nyeaons.catSpecies = "스코티시폴드"; // 묘종은 스코티시 폴드.
Nyeaons.color = "티끌없는 화이트"; // 색깔은 티끌없는 화이트.
Nyeaons.catAge = 5; // 나이는 5살.
Console.WriteLine($"이 고양이의 이름은 {Nyeaons.catName}다. 묘종은 {Nyeaons.catSpecies}이며, {Nyeaons.color}색을 지닌 귀여운 고양이지");
Console.WriteLine($"나이는 {Nyeaons.catAge.ToString()}살 이다");
Console.WriteLine($"{Nyeaons.catName} 물어!");
Nyeaons.moving();
Nyeaons.jump();
Nyeaons.meow();
}
}
>
** 객체의 정의를 보면, "클래스(class)가 실제로 구현된 인스턴스(instance)". 즉, Nyeaons는 인스턴스이자 객체이다.
개념의 혼동을 피하기 위해 chatGPT에 물어보았다..
II. OOP의 4가지 속성
A. 추상화 (Abstraction)
: 프로그램으로 표현하기 위하여, 실제의 개념을단순화하고 필요한 부분을 강조하여표현하는 개념.
!! 위에서 고양이에 대한 개념을
속성(Property) : 고양이 이름, 묘종, 색깔, 나이의 데이터로 고양이의 정보를 표현
메서드(Methods) : 우는 행동, 이동하는 것, 점프하는 것으로 고양이의 행동을 나타내는 기능을 표현함.
internal class Cat
{
// 속성 정의
public string catName; // 이름은 뭔지
public string catSpecies; // 묘종은 뭔지..
public string color; // 색은 뭔지..
public int catAge; // 나이는 몇 살인지..
// 기능 정의
public void meow() // 야옹하고 울기
{
Console.WriteLine("Meow!");
}
public void moving()
{
Console.WriteLine(catName + " is moving..."); // 이동하기
}
public void jump()
{
Console.WriteLine("...Jump!"); // 점프하기
}
}
B. 캡슐화 (Encapuslation)
: 데이터와 해당 데이터를 다루는 메서드를 하나의 단위로 묶어, 외부의 접근을 제어하고, 데이터를 보호하는 개념.
!! 접근 제한자 (Access Modifier) : 객체 지향 프로그래밍에서 클래스의 멤버(필드, 메서드, 속성 등)에 대한 접근 권한을 지정하는 키워드
1. public : 모든 외부의 접근을 허가함. 2. private : 같은 클래스 내에서만 접근을 허가함. 3. protected : 같은 클래스 내부와 파생 클래스에서 접근을 허가함. 4. internal : 같은 **어셈블리 내에서 접근을 허가함.
**어셈블리 (assembly) : NET 런타임 환경에서 실행할 수 있는 코드와 리소스, 메타데이터를 포장하고 배포하는 단위
!! 위에서 고양이의 정보(데이터) 와 행동(메서드) 을 하나의 단위로 캡슐화(Cat 클래스) 하였고, 외부 코드(Main) 에서 Cat 클래스를 사용하여 고양이를 다룸.
: 데이터의 보호를 위해서는 데이터의 선언을 필드로 직접 접근하기 보다는 속성(property) 으로 해야한다.
internal class Cat
{
public string catName; // !! 필드로 직접 접근하는 방식 : 외부 필드에서 변형이 가능하다.
private string _catAge // !! 속성으로 접근하는 방식 : 클래스 내에 _catAge 라는 속성을 추가.
public string catAge // !! 클래스 외부에서 private 필드에 접근하지 않고 속성을 통해 접근 가능해짐.
{
get { return _catAge; }
set { _catAge = value; }
}
: 클래스의 속성을 통해, 외부에서 Cat 클래스의 인스턴스를 생성하거나 속성을 설정할 때, 원하는 방식으로 데이터 처리가 가능해진다.
internal class Cat
{
public string catName; // !! 필드로 직접 접근하는 방식 : 외부 필드에서 변형이 가능하다.
private string _catAge // !! 속성으로 접근하는 방식 : 클래스 내에 _catAge 라는 속성을 추가.
public string catAge // !! 클래스 외부에서 private 필드에 접근하지 않고 속성을 통해 접근 가능해짐.
{
get { return _catAge; }
//set { _catAge = value; }
set
{
if (value > 0)
{
_catAge = value;
}
else
{
console.WriteLine("유효하지 않는 나이입니다."); // !! set 접근자의 조건문에 의해 나이가 잘못된 경우를 처리할 수 있게 됨.
_catAge = 99;
}
}
}
}
C. 상속 (Inheritance)
: 기존 클래스의 속성과 메서드를 새로운 클래스에서 재사용하거나 확장할 수 있게 해주는 개념.
!! 고양이와 비슷한 맥락으로 강아지의 클래스를 만듦.
internal class Dog
{
// 속성 정의
private string name;
public string Name // 이름은 뭔지..
{
get { return name; }
set { name = value; }
}
private string dogBreed;
public string DogBreed // 견종은 뭔지..
{
get; // !! 생략 가능함.
set;
}
private string color;
public string Color // 색은 뭔지..
{
get;
set;
}
private int age;
public int Age // 나이는 뭔지..
{
get { return age; }
set
{
if (value > 0)
{
age = value;
}
else
{
Console.WriteLine("유효하지 않은 나이입니다.");
age = 99;
}
}
}
// 기능 정의
public void bark() // 왈!하고 울기
{
Console.WriteLine("Bark!");
}
public void moving()
{
Console.WriteLine(Name + " is moving..."); // 이동하기
}
public void jump()
{
Console.WriteLine("...Jump!"); // 점프하기
}
}
>
!! 고양이 클래스와 비교해보았을 때, 다음의 클래스 멤버는 공통적으로 사용이 가능함을 알 수 있다.
속성 : 이름, 나이, 색 메서드 : 이동, 점프
!! 고양이와 강아지의 개념의 공통점은 동물이라는 점이다.
==> 해당하는 공유가능한 속성과 메서드를 상위 클래스(Animal) 로 추상화 시킨다면, 상위 클래스로부터 확장된 여러 개의 하위 클래스(Dog, Cat)에서 해당 속성과 메서드들을 간편하게 사용할 수 있다.
class Animal
{
// properties
private string name;
public string Name
{
get;
set;
}
private string color;
public string Color
{
get;
set;
}
private string age;
public string Age
{
get;
set;
}
// methods
public void moving()
{
Console.WriteLine($"{Name}이 움직이기 시작합니다."};
}
public void jump()
{
Console.WriteLine("...JUMP!"};
}
}
!! 하위 클래스의 선언은 하위 클래스 : 상위 클래스 로 하여, 상속이 이루어지게 한다.
internal class Dog : Animal
{
// properties
private string dogBreed;
public string DogBreed // 견종은 뭔지..
{
get; // !! 생략 가능함.
set;
}
// methods
public void bark() // 왈!하고 울기
{
Console.WriteLine("Bark!");
Console.WriteLine($"{Name}은 발랄하게 가서 물었다");
}
}
internal class Cat : Animal
{
// properties
private string _catSpecies;
public string catSpecies // 묘종은 뭔지..
{
get;
set;
}
// methods
public void meow() // 야옹하고 울기
{
Console.WriteLine("Meow!");
Console.WriteLine("아무 일도 일어나지 않았다.");
}
}
!! Main에서 실행
Nyeaons & Mungs
internal class Program
{
static void Main(string[] args)
{
Cat Nyeaons = new Cat();
Nyeaons.Name = "Nyeaons"; // 고양이의 이름은 냬옹스다.
Nyeaons.catSpecies = "스코티시폴드"; // 묘종은 스코티시 폴드.
Nyeaons.Color = "티끌없는 화이트"; // 색깔은 티끌없는 화이트.
Nyeaons.Age = 5; // 나이는 5살.
Console.WriteLine($"이 고양이의 이름은 {Nyeaons.Name}다. 묘종은 {Nyeaons.catSpecies}이며, {Nyeaons.Color}색을 지닌 귀여운 고양이지");
Console.WriteLine($"나이는 {Nyeaons.Age.ToString()}살 이다\n\n");
Console.WriteLine($"{Nyeaons.Name} 물어!");
Nyeaons.moving();
Nyeaons.jump();
Nyeaons.meow();
Console.WriteLine("\n\n");
Dog Mungs = new Dog();
Mungs.Name = "Mungs"; // 강아지의 이름은 멍스다.
Mungs.DogBreed = "웰시코기"; // 견종은 웰시코기
Mungs.Color = "갓 구운 빵과 같은 풍부한 브라운"; // 색깔은 이하 동문
Mungs.Age = 3; // 나이는 3살
Console.WriteLine($"이 강아지의 이름은 {Mungs.Name}다. 견종은 {Mungs.DogBreed}이며, {Mungs.Color}색을 지닌 귀여운 강아지라구");
Console.WriteLine($"나이는 {Mungs.Age.ToString()}살 이다\n\n");
Console.WriteLine($"{Mungs.Name} 물어!");
Mungs.moving();
Mungs.jump();
Mungs.bark();
Console.WriteLine("\n\n");
}
}
>
D. 다형성 (Polymorphism)
: 어떤 객체의 속성이나 기능이 그 맥락에 따라 다른 역할을 수행할수 있는 객체 지향의 특성
메서드 오버라이딩 (Method Overriding) : 상속 관계에서 자식 클래스가 부모 클래스의 메서드를 재정의하여 사용하는 것. : 같은 이름의 기능이 다른 역할을 수행할 때 사용.
ex) 위의 코드에서 고양이와 강아지에게 물어! 라고 시켰는데 다른 결과가 나옴. 이를 동일한 이름으로 재정의 한 후, 메서드 오버라이딩을 수행 했을 때.
class Animal
{
// properties
private string name;
public string Name
{
get;
set;
}
// methods
public virtual void Command() // 해당 메서드는 오버라이드 가능하다 선언.
{
Console.WriteLine("동물에게 명령해보았다.");
Console.WriteLine($"{Name}이 움직이기 시작합니다.");
Console.WriteLine("...JUMP!");
}
}
class Dog : Animal
{
public override void Command() // 왈!하고 울기
{
Console.WriteLine($"{Name} 물어!");
Console.WriteLine($"{Name}이 움직이기 시작합니다.");
Console.WriteLine("...JUMP!");
Console.WriteLine("Bark!");
Console.WriteLine($"{Name}은 발랄하게 가서 물었다");
}
}
class Cat : Animal
{
public override void Command() // 야옹하고 울기
{
Console.WriteLine($"{Name} 물어!");
Console.WriteLine($"{Name}이 움직이기 시작합니다.");
Console.WriteLine("...JUMP!");
Console.WriteLine("Meow!");
Console.WriteLine("아무 일도 일어나지 않았다.");
}
}
==> Main에서 사용하는 명령 부분을 상당히 줄일 수 있었다.
static void Main(string[] args)
{
Cat Nyeaons = new Cat();
Nyeaons.Name = "Nyeaons"; // 고양이의 이름은 냬옹스다.
Nyeaons.catSpecies = "스코티시폴드"; // 묘종은 스코티시 폴드.
Nyeaons.Color = "티끌없는 화이트"; // 색깔은 티끌없는 화이트.
Nyeaons.Age = 5; // 나이는 5살.
Console.WriteLine($"이 고양이의 이름은 {Nyeaons.Name}다. 묘종은 {Nyeaons.catSpecies}이며, {Nyeaons.Color}색을 지닌 귀여운 고양이지");
Console.WriteLine($"나이는 {Nyeaons.Age.ToString()}살 이다\n\n");
Nyeaons.Command();
/* 이하의 부분이 생략됨.
Console.WriteLine($"{Name} 물어!");
Console.WriteLine($"{Name}이 움직이기 시작합니다.");
Console.WriteLine("...JUMP!");
Console.WriteLine("Meow!");
Console.WriteLine("아무 일도 일어나지 않았다.");
Console.WriteLine("\n\n");
*/
// 생략...
인터페이스 (Interface) : 메서드의 이름, 매개변수, 반환 유형만을 선언없이 정의함으로써, 상속받는 클래스에 해당 메서드를 강제함. : 다중 상속이 가능함. : 클래스 간의 관계를 유연하게 설계할 수 있음.
ex) 각 동물의 소개를 Iintroduce라는 인터페이스를 활용하여 Main에 적용
// 소개문 인터페이스
internal interface Iintroduce
{
string Introduce();
}
internal class Dog : Animal, Iintroduce
{
//.. 생략
public string Introduce()
{
return ($"이 강아지의 이름은 {Name}다. 견종은 {DogBreed}이며, {Color}색을 지닌 귀여운 강아지라구\n나이는 {Age.ToString()}살 이다\n\n");
}
}
internal class Cat : Animal, Iintroduce
{
//.. 생략
public string Introduce()
{
return ($"이 고양이의 이름은 {Name}다. 묘종은 {catSpecies}이며, {Color}색을 지닌 귀여운 고양이지\n나이는 {Age.ToString()}살 이다\n\n");
}
}
==> 마찬가지로, main에서 일일히 적용시켜주지 않아도 됨.
internal class Program
{
static void Main(string[] args)
{
Cat Nyeaons = new Cat();
Nyeaons.Name = "Nyeaons";
Nyeaons.catSpecies = "스코티시폴드";
Nyeaons.Color = "티끌없는 화이트";
Nyeaons.Age = 5;
Console.WriteLine(Nyeaons.Introduce()); // 인터페이스로 인한 소개문 생략
Nyeaons.Command(); // 오버라이드로 인한 명령 부분 생략
Dog Mungs = new Dog();
Mungs.Name = "Mungs";
Mungs.DogBreed = "웰시코기";
Mungs.Color = "갓 구운 빵과 같은 풍부한 브라운";
Mungs.Age = 3;
Console.WriteLine(Mungs.Introduce());
Mungs.Command();
}
}