안녕하세요! 이번 글은 자바 프로그래밍 입문 11번째 포스팅으로 디자인 패턴에 관한 이야기입니다.
프로그램을 설계하다보면 어떤 특정한 곳에서 고질적인 문제들이 종종 발생합니다. 이 때 우리는 디자인 패턴이라는 것을 통해 특정 문제가 발생하게 되면 그 문제를 해결할 수 있는 수단으로서 재사용 가능한 일련의 해결책을 만들어놓는데, 이것이 바로 디자인 패턴입니다.
그러면 디자인 패턴에 대해 자세하게 알아보겠습니다.
디자인 패턴이라고 하면 보통 객체지향 프로그래밍에서 등장하는 키워드입니다.
디자인 패턴은 객체지향 프로그래밍에 관한 설계를 할 때 자주 발생할만한 문제들을 피하기 위해 만들어두는 패턴이라고 정의할 수 있습니다.
이러한 디자인 패턴의 종류는 세가지의 타입으로 나눕니다.
생성(Creational) 패턴 | 구조(Structure) 패턴 | 행위(Behavioral) 패턴 |
---|---|---|
- 추상 팩토리(Abstract Factory) - 빌더(Builder) - 팩토리 메서드(Factory Method) - 프로토타입(Prototype) - 싱글턴(Singleton) | - 어댑터(Adapter) - 브리지(Bridge) - 컴퍼짓(Composite) - 데코레이터(Decorator) - 퍼서드(Facade) - 플라이웨이트(Flyweight) - 프록시(Proxy) | - 책임연쇄(Chain of Responsibility) - 커맨드(Command) - 인터프리터(Interpreter) - 이터레이터(Iterator) - 미디에이터(Mediator) - 옵서버(Observer) - 스테이트(State) - 스트래티지(Strategy) - 템플릿메서드(Template Method) - 비지터(Visitor) |
생성 패턴은 객체의 생성과 관련된 패턴입니다.
객체 생성 시 캡슐화를 통해 특정 객체가 변형되거나 다른 객체가 만들어지더라도 프로그램 구조에 영향을 받지 않도록 하게 하는 것이지요.
우리가 오늘 자세하게 살펴볼 내용은 싱글턴에 관한 내용입니다.
구조 패턴은 클래스나 객체를 조합해서 더 큰 규모로 확장시켜줍니다.
가령 서로 다르게 생긴 인터페이스를 상속받는 두 개의 객체를 엮어서 또 다른 인터페이스를 만들거나 객체들을 서로 모아서 다른 새로운 기능을 제공해주는 객체를 만드는 패턴입니다.
행위 패턴은 객체나 클래스간 알고리즘이나 책임의 분배에 관한 패턴입니다.
어떤 객체가 혼자서만 수행할 수 없는 작업에 대해 어떻게 여러개의 객체로 분배해주는지, 분배의 과정에서 객체 사이의 결합정도를 최소화 함에 중점을 둡니다.
Singleton
앞서 말한것처럼 싱글톤이라는 것은 전역변수를 사용하지 않고 객체를 하나만 생성해서 생성된 객체를 어디에서든 참조할 수 있게 해줍니다.
전역변수를 사용하지 않고 객체를 하나만 생성해서 어디서든 참조하게 하려면 어떻게 해야 할까요?
우리는 public static 클래스 이름
과 같은 형태를 사용했습니다. static
은 정적 변수로서 사용되며 변수 뿐만 아니라 함수나 메서드에 붙을 수 있습니다.
싱글톤은 클래스 외부에서 new
연산자로 생성자를 호출해 생성할 수 없도록 해주어야 합니다. 그렇게 하기 위해서 접근 제어자는 private
로 하고 싱글톤을 선언해주어야 합니다. 또한 외부에서 내부의 값을 변경하지 못하게 해줍니다.
이 때 정적필드(static
)로 선언하여 자신의 객체를 생성 때 초기화 되어야 합니다. 싱글톤 내에서는 new
연산자로 생성자의 호출이 가능합니다.
싱글톤을 외부에서 호출할 수 있는 메서드는 getInstance()
이며 정적 필드에서 참조하는 자신 객체를 리턴해줍니다. 일반 클래스가 자신을 정의할 때는 생성자를 사용하는데 이와는 조금 다르죠?
// 싱글톤 만드는 방법
public class Singleton {
// 정적필드
private static Singleton singleton = new Singleton();
// 생성자
private Singleton() {}
// 정적 메서드
static singleton getInstance() {
return singleton;
}
}
외부에서 우리가 작성한 싱글톤 객체를 참조하기 위해 할 수 있는 유일한 방법은 Singleton
객체 내부의 메서드를 호출하는 것입니다. 이 때 우리는 getInstance()
를 쓸 수 있습니다.
getInstance()
는 하나의 객체를 리턴해주기 때문에 같은 싱글턴 객체로 만든 변수가 있다면 이는 같은 객체를 참조하기 때문에 변수는 모두 같은 값으로 나오게 됩니다.
이렇게 서로 다른 변수로 선언되었지만 같은 객체의 메모리 주소를 참조하게 되므로 두 개 객체의 주소값을 비교해보면 같습니다.
사람의 정보를 담는 싱글톤 클래스를 작성해보겠습니다.
// MyClass
package Singleton
public class Singleton {
private static Singleton singleton = null; // 객체 내부에서 new 연산자 사용 가능
private int number;
private String name;
private Signleton() {}
public static Singleton getInstance() {
return singleton;
}
}
이를 바탕으로 새로운 객체를 만들어줍시다.
// MyClass
package cls;
import Singleton.Singleton;
public class MyClass {
private int number;
private String name;
public MyClass(int number, String name) {
number = 1001;
name = "홍길동";
}
public void method() {
Singleton s = Singleton.getInstance();
s.number = number;
s.name = name;
}
}
메인 함수에서 호출해줍시다.
package Main;
import Singleton.Singleton;
import cls.MyClass;
public class Main {
public static void main(String[] args) {
MyClass mycls = new MyClass();
mycls.method();
}
}
오늘은 이렇게 디자인 패턴 중 싱글톤에 대해 알아봤습니다. 복습에 많은 도움이 되시길 바랍니다.