* GRASP Pattern
General Responsibility Assignment Software Patterns의 약자로,
Object-Orinted-Programing의 핵심중 하나인 객체에 책임을 부여하는 원칙을 기술한 패턴.
총 9가지 원칙을 가지고 있다.
1. Information Expert : 정보 은닉의 원칙
- 데이터를 가지고 있는 객체에 책임을 부여하라. (getter 함수를 덜 사용하게 되겠다..)
- 객체는 데이터와 처리 로직이 함께 묶여 있어야 한다.
- 정보 은닉을 통해 자신의 데이터를 감추고, 오직 Method로만 데이터를 처리하고, 외부에는 그 기능(책임)만 제공한다.
2. Creator : 객체 생성의 원칙
- 객체의 생성은 '생성될 객체'의 컨텍스트를 알고 있는 다른 객체가 있다면, 알고 있는 객체에 책임 부여.
- ex) A, B 객체의 관계가 아래 중 하나라면 A의 생성을 B의 책임으로 부여.
- B 객체가 A 객체를 포함
- B 객체가 A 객체의 정보를 기록하고 있음
- A 객체가 B 객체의 일부
- B 객체가 A 객체를 긴밀하게 사용
- B 객체가 A 객체의 생성에 필요한 정보를 가지고 있음.
Factory Pattern 참고?
글로만 봐서는 이해가 조금 힘든데, 아래 자전거를 만드는 예시를 보자.
public class Bike {
private Wheel wheel;
private Frame frame;
Bike(Wheel wheel, Frame frame) { // Creator 패턴을 사용하지 않은 생성자 1
this.wheel = wheel;
this.frame = frame;
}
Bike(int weelWid, int frameLen) { // Creator 패턴을 사용한 생성자 2
this.weel = new Wheel(weelWid);
this.frame = new Frame(frameLen);
}
public static void main(String[] args) {
// 생성자 1을 사용해 객체 생성
Wheel wheel = new Wheel(24);
Frame frame = new Frame(52);
Bike bike1 = new Bike(wheel, frame);
// 생성자 2를 사용해 객체 생성
Bike bike2 = new Bike(24, 52);
}
}
생성자 2에선 Creator 패턴에 따라 Wheel, Frame 객체 생성을 이 객체를 일부로 하는 Bike 객체에서 직접 생성했다.
생각 없이 코딩하다 보면 생성자 1 처럼 객체를 생성하게 되는데, 이 패턴을 고민하면서 객체를 생성해 보자.
3. Controller
- 시스템 이벤트(사용자의 요청)를 처리할 객체를 만들자.
4. Low Coupling
- 객체들간, 서브 시스템들 간의 상호 의존도가 낮게 책임을 부여
- Low Coupling은 각 객체, 서브시스템의 재사용성을 높이고, 시스템 관리에 편하게 한다.
- Object-Orinted 시스템은 각 객체들 간의 Comunication을 통해 비즈니스 완성
- 따라서 각 객체들 상에 Coupling이 존재하지 않을 수는 없다.
5. High Cohesion
- 각 객체가 밀접하게 연관된 책임들만 가지도록 구성하라.
- 한 객체, 한 시스템이 자기 자신이 부여받은 책임만을 수행하도록 구성되있다면, 자연스럽게 Low Coupling이 된다.
6. Polymorphism : 다형성
- 객체의 종류에 따라 행동양식이 바뀐다면, Polymorphism 기능을 사용하라.
- 조건문을 통해 종류레 따라 행동을 바꾸지 말고 Polymorphism을 사용.
두 개의 다른 SilverSeller에서 SIlver의 가격을 가져오는 프로그램을 작성할 때,
If 문을 사용해 각 Seller에게서 가격을 받아오지 말고,
Seller를 하나의 abstract Class를 extends (혹은 Interface implements) 하면 if문 사용 없이 할 수 있다.
SilverSeller를 하나로 묶어줄 abstract class
public abstract class GetSilverPrice {
abstract public double getPricdOfSilver();
public String getName() {
return null;
}
}
판매처 1: ABCSilver
public class ABCSilver extends GetSilverPrice{
private String silverPrice = "SLV 30.66";
private String name = "ABC Silver";
public double getPriceOfSilver() {
String stringPrice = silverPrice.substring(4);
return Double.paesDouble(StringPrice);
}
publuc String getName() { return name; }
}
판매처 2: XYZSilver
public class XYZSilver extends GetSIlverPrice{
private String silverPrice = "30.67 Silver Ask price";
private String name = "XYZ Silver";
public double getPriceOfSilver() {
Strung[] stringprice = silverPrice.split(" ");
return Double.parseDouble(stringPrice[0]);
}
public String getName(){ return name; }
}
if문 없이 각 Seller를 조회하는 방법
public class SilverPrices {
public static void main(String[] args{
List<GetSilverPrice> silverSellers = new ArrayList<>();
silverSellers.add(new ABCSilver());
silverSellers.add(new XYZSilver());
for(GetSilverPrice silverPrice : silverSellers){
System.out.println(silverPrice.getName() + ": " + silverPrice.getPriceOfSilver());
}
}
}
7. Pure Fabrication
- 도메인에 관련된 문제를 대표하는 것이 아니라면, 기능적인 책임을 별도로 한 곳으로 관리하는 객체를 만들자.
아래와 같이 Sale 클래스에 데이터 정보와 그 데이터에 접근하는 메서드들이 있다. (코드는 생략)
public class Sale {
Data data;
String[] items;
double[] itemPrices;
double pruchaseAmt;
public void InsertInDatabase() {
//...
}
public void UpdateDatabase() {
//...
}
public void DeleteFromDatabase() {
//...
}
}
이 경우 아래와 같이 데이터에 접근하는 클래스를 분리하는 것이 Pure Fabrication Pattern이다.
public class Sale {
Data data;
String[] items;
double[] itemPrices;
double pruchaseAmt;
}
public class AccessDatabase {
Sale sale;
public void InsertInDatabase() {
//...
}
public void UpdateDatabase() {
//...
}
public void DeleteFromDatabase() {
//...
}
}
8. Indirection
- 두 객체 사이의 직접적인 Coupling을 피하고 싶다면, 그 사이에 다른 매개체를 통해 전달받아라.
- 주로 인터페이스를 많이 쓰인다.
- GOF의 Adapter, Bridge, Facade, Observer, Mediator 가 해당된다.
public interface EnemyAttacker{
public void attack();
}
public class EnemyTank implements EnemyAttacker{
public void attack() {
System.out.println("Tank fires 2 missiles");
}
}
public class EnemyRobot {
public void jumpOnEnemy(){
System.out.println("Robot jumps on the enemy");
}
}
public class EnemyRoboyAdapter implement EnemyAttacker {
private EnemyRobot robot;
public EnemyRobotAdapter(EnemyRobot robot) {
this.robot = roboy;
}
public void attack() {
robot.jumpOnEnemy();
}
}
public class TestAdapter{
public static void main(String[] args) {
EmentAttacker tank = new EnemyTank();
EnemyRobot robot = new EnemyRobot();
EnemyAttacker robotAdapter = new EnemyRobotAdapter(robot);
tank.attack();
robotAdapter.attack();
}
}
9. Protected Variations
- 변경될 여지가 있는 곳에 안정된 인터페이스를 정의해 사용하자.
출처: https://www.hanbit.co.kr/channel/category/category_view.html?cms_code=CMS8586826397
'코딩 > Software Architecture' 카테고리의 다른 글
| [GoF Design Pattern] State (1) | 2022.12.24 |
|---|---|
| [GoF Design Pattern] Abstract Factory (0) | 2022.12.24 |
| [GoF Design Pattern] Chain of Responsibility (0) | 2022.12.06 |
| [GoF Design Pattern] Mediator (0) | 2022.12.06 |
| [GoF Design Pattern] Decorator (0) | 2022.12.05 |