Skip to content

Latest commit

ย 

History

History
565 lines (318 loc) ยท 15.1 KB

android-architecture-pattern.md

File metadata and controls

565 lines (318 loc) ยท 15.1 KB

android-architecture-pattern

Android Architecture Pattern์ธ MVC, MVP, MVVM์— ๋Œ€ํ•˜์—ฌ.

Present Time : 2018-06-03-SUN

Presentation File : https://github.com/ParkSohyeon17/TIL/blob/master/Android/MVC%2C%20MVVM%2C%20MVP.pptx

Last Updated : 2018-06-04-MON


0. ๊ณต์‹ ๋ฌธ์„œ

0-1. ๋ ˆํผ๋Ÿฐ์Šค

0-2. ๊ฐ€์ด๋“œ


์˜ˆ์ œ ์ฝ”๋“œ ์ถœ์ฒ˜ : STEVE.JUNG

public class MainActivity extends AppCompatActivity {
    private TextView textView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        textView = (TextView) findViewById(R.id.btn_confirm);
        textView.setText("Non-Clicked");

        findViewById(R.id.btn_confirm).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                TextView textView = (TextView) findViewById(R.id.btn_confirm);
                textView.setText(getClickedText());
            }
        });
    }

    private String getClickedText() {
        return "Clicked!!!";
    }
}

1. MVC

Both the Controller and the View depend on the Model: the Controller to update the data, the View to get the data.

๋“ฑ์žฅ์‹œ๊ธฐ

  • ๊ทธ๋ž˜ํ”ฝ ์‚ฌ์šฉ์ž ์ธํ„ฐํŽ˜์ด์Šค์˜ ์ดˆ๊ธฐ ๊ฐœ๋ฐœ์— ๋Œ€ํ•œ ํ†ต์ฐฐ๋ ฅ ์ค‘ ํ•˜๋‚˜์ด๋‹ค.
  • MVC๋Š” ์ฑ…์ž„๊ณผ ๊ด€๋ จํ•˜์—ฌ ์†Œํ”„ํŠธ์›จ์–ด ๊ตฌ์„ฑ์„ ์„ค๋ช…ํ•˜๊ณ  ๊ตฌํ˜„ํ•˜๋Š” ์ฒซ ๋ฒˆ์งธ ๋ฐฉ๋ฒ• ์ค‘ ํ•˜๋‚˜๊ฐ€ ๋˜์—ˆ๋‹ค.
  • Trygve Reenskaug๋Š” 1970 ๋…„๋Œ€์— Xerox Palo Alto Research Center(PARC)๋ฅผ ๋ฐฉ๋ฌธํ•˜๋ฉด์„œ Smalltalk -76์— MVC๋ฅผ ๋„์ž…ํ–ˆ๋‹ค.

๋“ฑ์žฅ์ด์œ 

  • ์‚ฌ์šฉ์ž ์ธํ„ฐํŽ˜์ด์Šค ๋กœ์ง์ด ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง๋ณด๋‹ค ์ž์ฃผ ๋ณ€๊ฒฝ๋˜๋Š” ๊ฒฝํ–ฅ์ด ์žˆ๋Š” ์„ธ๊ณ„

  • ๊ฐ ๊ณ„์ธต์„ ๋ถ„๋ฆฌ์‹œํ‚ด์œผ๋กœ์จ ์ฝ”๋“œ์˜ ์žฌํ™œ์šฉ์„ฑ์„ ๋†’์ด๊ณ  ๋ถˆํ•„์š”ํ•œ ์ค‘๋ณต์„ ๋ง‰๊ธฐ์œ„ํ•ด์„œ

์ •์˜

Model-View-Controller ํด๋ž˜์Šค ๊ตฌ์กฐ

  • Model : ๋น„์ฆˆ๋‹ˆ์Šค ๊ณ„์ธต ๊ด€๋ฆฌ. ๋„คํŠธ์›Œํฌ ๋˜๋Š” ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค API๋ฅผ ์ฒ˜๋ฆฌํ•˜๋Š” ๋ฐ์ดํ„ฐ ๊ณ„์ธต
  • View : ๋ชจ๋ธ์˜ ๋ฐ์ดํ„ฐ๋ฅผ ์‹œ๊ฐํ™”. ์ฆ‰, UI Layer.
  • Controller : Logic Layer์€ ์‚ฌ์šฉ์ž ํ–‰๋™์„ ํ†ต์ง€ ๋ฐ›๊ณ  ํ•„์š”์— ๋”ฐ๋ผ ๋ชจ๋ธ์„ ์—…๋ฐ์ดํŠธํ•จ.

ํŠน์ง•

  • Model

    • ์ •์˜์™€ ๊ฐ™๋‹ค.
  • View

    • ๋ทฐ๋Š” ํ•˜์œ„ ๋ชจ๋ธ์— ๋Œ€ํ•œ ์ง€์‹์ด๋‚˜ ์ƒํƒœ์— ๋Œ€ํ•œ ์ดํ•ด๊ฐ€ ์—†๊ณ , ์‚ฌ์šฉ์ž๊ฐ€ ๋ฒ„ํŠผ์„ ํด๋ฆญํ•˜๊ฑฐ๋‚˜ ๊ฐ’์„ ์ž…๋ ฅํ•˜๋Š” ๋“ฑ์˜ ํ–‰๋™์„ ํ•  ๋•Œ ๋ฌด์—‡์„ ํ•ด์•ผ ํ•˜๋Š”์ง€ ๋ชจ๋ฅธ๋‹ค.

      ๋ทฐ๊ฐ€ ๋œ ์•Œ์ˆ˜๋ก ๋ชจ๋ธ์— ์ข…์†๋˜์ง€ ์•Š์œผ๋ฏ€๋กœ ๋ณด๋‹ค ๋ณ€ํ™”์— ์œ ์—ฐํ•  ์ˆ˜ ์žˆ๋‹ค.

  • Controller

    • ์•ฑ์„ ๋ฌถ์–ด์ฃผ๋Š” ์ ‘์ฐฉ์ œ

    • ๋ทฐ๊ฐ€ ์ปจํŠธ๋กค๋Ÿฌ์—๊ฒŒ ์‚ฌ์šฉ์ž๊ฐ€ ๋ฒ„ํŠผ์„ ๋ˆŒ๋ €๋‹ค๊ณ  ์•Œ๋ฆฌ๋ฉด, ์ปจํŠธ๋กค๋Ÿฌ๋Š” ๊ทธ์— ๋”ฐ๋ผ ์–ด๋–ป๊ฒŒ ๋ชจ๋ธ๊ณผ ์ƒํ˜ธ์ž‘์šฉํ• ์ง€ ๊ฒฐ์ •ํ•œ๋‹ค.

    • ๋ชจ๋ธ์—์„œ ๋ฐ์ดํ„ฐ๊ฐ€ ๋ณ€ํ™”๋˜๋Š” ๊ฒƒ์— ๋”ฐ๋ผ ์ปจํŠธ๋กค๋Ÿฌ๋Š” ๋ทฐ์˜ ์ƒํƒœ๋ฅผ ์ ์ ˆํ•˜๊ฒŒ ์—…๋ฐ์ดํŠธํ•˜๋„๋ก ๊ฒฐ์ •ํ•  ์ˆ˜ ์žˆ๋‹ค.

    • ์•ˆ๋“œ๋กœ์ด๋“œ ์•ฑ์—์„œ๋Š” ์ปจํŠธ๋กค๋Ÿฌ๊ฐ€ ์ฃผ๋กœ ์•กํ‹ฐ๋น„ํ‹ฐ๋‚˜ ํ”„๋ž˜๊ทธ๋จผํŠธ๋กœ ํ‘œํ˜„๋œ๋‹ค.

      โ€‹

์žฅ์ 

  • ์ฝ”๋“œ์˜ ํ…Œ์ŠคํŠธ ๊ฐ€๋Šฅ์„ฑ์ด ํ–ฅ์ƒ๋œ๋‹ค.

  • ํ™•์žฅ์ด ์šฉ์ดํ•˜์—ฌ ์ƒˆ๋กœ์šด ๊ธฐ๋Šฅ์„ ์‰ฝ๊ฒŒ ๊ตฌํ˜„ํ•  ์ˆ˜ ์žˆ๋‹ค.

  • Model ํด๋ž˜์Šค๋Š” Android ํด๋ž˜์Šค์— ๋Œ€ํ•œ ์ฐธ์กฐ๊ฐ€ ์—†์œผ๋ฏ€๋กœ ๋‹จ์œ„ ํ…Œ์ŠคํŠธ์— ๊ฐ€๋Šฅํ•˜๋‹ค. ๋งˆ์ฐฌ๊ฐ€์ง€๋กœ Controller์˜ ๋‹จ์œ„ํ…Œ์ŠคํŠธ๋„ ๊ฐ€๋Šฅํ•˜๋‹ค.

    โ€‹

  • -๋ชจ๋ธ์ด ์–ด๋””์—๋„ ์ข…์†๋˜์ง€ ์•Š์œผ๋ฉฐ, ๋ทฐ๋Š” ์œ ๋‹› ํ…Œ์ŠคํŠธ ๋ ˆ๋ฒจ์—์„œ ๊ทธ๋‹ค์ง€ ํ…Œ์ŠคํŠธํ•  ๊ฒƒ์ด ๊ฑฐ์˜ ์—†์–ด์„œ ์‰ฝ๊ฒŒ ๋ชจ๋ธ์„ ํ…Œ์ŠคํŠธํ•  ์ˆ˜ ์žˆ๋‹ค. ํ™•์žฅ์ด ์šฉ์ดํ•˜์—ฌ ์ƒˆ๋กœ์šด ๊ธฐ๋Šฅ์„ ์‰ฝ๊ฒŒ ๊ตฌํ˜„ํ•  ์ˆ˜ ์žˆ๋‹ค.

    โ€‹

๋‹จ์ 

  • View๊ฐ€ Controller์™€ Model ๋ชจ๋‘์— ์˜์กดํ•œ๋‹ค๋Š” ์ ์„ ๊ฐ์•ˆํ•  ๋•Œ, UI Logic์˜ ๋ณ€๊ฒฝ์€ ์—ฌ๋Ÿฌ ํด๋ž˜์Šค์˜ ์—…๋ฐ์ดํŠธ๊ฐ€ ํ•„์š”ํ•  ์ˆ˜ ์žˆ์œผ๋ฏ€๋กœ ํŒจํ„ด์˜ ์œ ์—ฐ์„ฑ์ด ๋–จ์–ด์ง„๋‹ค.

    โ€‹

  • View์™€ Model์ด ์„œ๋กœ ์˜์กด์ ์ด๋‹ค.

    โ€‹

Controller ๋‹จ์ 

  • ํ…Œ์ŠคํŠธ ์šฉ์ด์„ฑ : ์ปจํŠธ๋กค๋Ÿฌ๊ฐ€ ์•ˆ๋“œ๋กœ์ด๋“œ API์— ๊นŠ๊ฒŒ ์ข…์†๋˜๋ฏ€๋กœ ์œ ๋‹› ํ…Œ์ŠคํŠธ๊ฐ€ ์–ด๋ ต์Šต๋‹ˆ๋‹ค.
  • ๋ชจ๋“ˆํ™” ๋ฐ ์œ ์—ฐ์„ฑ : ์ปจํŠธ๋กค๋Ÿฌ๊ฐ€ ๋ทฐ์— ๋‹จ๋‹จํžˆ ๊ฒฐํ•ฉ๋˜๋ฉฐ, ๋ทฐ์˜ ํ™•์žฅ์ผ ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค. ๋ทฐ๋ฅผ ๋ณ€๊ฒฝํ•˜๋ฉด ์ปจํŠธ๋กค๋Ÿฌ๋กœ ๋Œ์•„๊ฐ€์„œ ๋ณ€๊ฒฝํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.
  • ์œ ์ง€ ๋ณด์ˆ˜ : ์‹œ๊ฐ„์ด ์ง€๋‚จ์— ๋”ฐ๋ผ ๋ณด๋‹ค ๋งŽ์€ ์ฝ”๋“œ๊ฐ€ ์ปจํŠธ๋กค๋Ÿฌ๋กœ ๋ชจ์ด๋ฉด์„œ ๋น„๋Œ€ํ•ด์ง€๊ณ  ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•˜๊ธฐ ์‰ฌ์›Œ์ง‘๋‹ˆ๋‹ค. ํŠนํžˆ *anemic models ๋ชจ๋ธ์„ ์‚ฌ์šฉํ•˜๋Š” ์•ฑ์—์„œ๋ผ๋ฉด ๋”์šฑ ๊ทธ๋ ‡์Šต๋‹ˆ๋‹ค.

*anemic models ?

๋นˆ์•ฝํ•œ ๋„๋ฉ”์ธ ๋ชจ๋ธ. ๋ชจ๋“  ๋„๋ฉ”์ธ ๋กœ์ง์ด ์„œ๋น„์Šค ๊ณ„์ธต์— ์žˆ๋‹ค๋ฉด, ์—ฌ๋Ÿฌ๋ถ„์€ ์Šค์Šค๋กœ๋ฅผ ์žฅ๋‹˜์œผ๋กœ ๋งŒ๋“  ๊ฒƒ์ด๋‚˜ ๋‹ค๋ฆ„์—†๋‹ค.

์˜ˆ์ œ ์ฝ”๋“œ

public class MainActivity extends AppCompatActivity {
    private MainModel mainModel;
    private TextView textView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        mainModel = new MainModel();

        textView = (TextView) findViewById(R.id.btn_confirm);
        textView.setText("Non-Clicked");

        findViewById(R.id.btn_confirm).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                String text = mainModel.getClickedText();
                TextView textView = (TextView) findViewById(R.id.btn_confirm);
                textView.setText(mainModel.getClickedText());
            }
        });
    }

}
public class MainModel {
    public String getClickedText() {
        return "Clicked!!!";
    }
}

1-1. Passive Model

Passive Model Class Structure

1-1-1. ํŠน์ง•

  • Controller๋Š” Model์„ ์กฐ์ž‘ํ•˜๋Š” ์œ ์ผํ•œ ํด๋ž˜์Šค.

  • ์‚ฌ์šฉ์ž์˜ ๋™์ž‘์— ๋”ฐ๋ผ Controller๋Š” Model์„ ์ˆ˜์ •ํ•ด์•ผ ํ•œ๋‹ค.

  • Model์ด ์—…๋ฐ์ดํŠธ ๋œ ํ›„์— Controller๋Š” View๋ฅผ ์—…๋ฐ์ดํŠธํ•ด์•ผ ํ•จ์„ ์•Œ๋ฆฐ๋‹ค. View๋Š” Model๋กœ๋ถ€ํ„ฐ ๋ฐ์ดํ„ฐ๋ฅผ ์š”์ฒญํ•œ๋‹ค.

    โ€‹

1-2. Active Model

Active Model Class Structure

1-2-1. ํŠน์ง•

  • Controller๋Š” Model์„ ์ˆ˜์ •ํ•˜๋Š” ์œ ์ผํ•œ ํด๋ž˜์Šค๊ฐ€ ์•„๋‹Œ ๊ฒฝ์šฐ ๋ชจ๋ธ์€ Observer Pattern์˜ ๋„์›€์„ ๋ฐ›์•„ View ๋ฐ ๊ธฐํƒ€ ํด๋ž˜์Šค์— ์—…๋ฐ์ดํŠธ๋ฅผ ์•Œ๋ฆฐ๋‹ค.

  • Model์—๋Š” ์—…๋ฐ์ดํŠธ์— ๊ด€์‹ฌ์ด ์žˆ๋Š” Observer ์ปฌ๋ ‰์…˜์ด ํฌํ•จ๋˜์–ด ์žˆ๋‹ค.

  • View๋Š” Observer interface๋ฅผ ๊ตฌํ˜„ํ•˜๊ณ  Observer๋ฅผ Model์— ๋“ฑ๋กํ•œ๋‹ค.

  • Model์ด ์—…๋ฐ์ดํŠธ ๋  ๋•Œ๋งˆ๋‹ค Observer ์ปฌ๋ ‰์…˜์„ ๋ฐ˜๋ณตํ•˜์—ฌ update๋ฉ”์†Œ๋“œ๋ฅผ ํ˜ธ์ถœํ•œ๋‹ค. View์—์„œ ์ด ๋ฉ”์†Œ๋“œ๋ฅผ ๊ตฌํ˜„ํ•˜๋ฉด Model์˜ ์ตœ์‹  ๋ฐ์ดํ„ฐ ์š”์ฒญ์ด ํŠธ๋ฆฌ๊ฑฐ๋œ๋‹ค.

    โ€‹

Active Model Behavior

2. MVP

Since the View and the Presenter work closely together, they need to have a reference to one another. To make the Presenter unit testable with JUnit, the View is abstracted and an interface for it used. The relationship between the Presenter and its corresponding View is defined in a Contract interface class, making the code more readable and the connection between the two easier to understand.

๋“ฑ์žฅ์‹œ๊ธฐ

  • MVC ํŒจํ„ด์˜ ๋‹จ์ ์„ ๋ณด์™„ํ•˜๊ธฐ ์œ„ํ•˜์—ฌ ๋“ฑ์žฅํ•œ ํŒจํ„ด.

  • MVC ํŒจํ„ด์€ ๋ทฐ๊ฐ€ ๋ชจ๋ธ์— ๊ฐ•๋ ฅํ•˜๊ฒŒ ์˜์กดํ•œ๋‹ค. MVP๋Š” ๊ฐ ์š”์†Œ๋ฅผ ๋ช…ํ™•ํ•˜๊ฒŒ ๋ถ„๋ฆฌํ•˜์—ฌ ์ปคํ”Œ๋ง์„ ๋‚ฎ์ถ”๊ธฐ ์œ„ํ•ด ๋“ฑ์žฅํ–ˆ๋‹ค.

    โ€‹

์ •์˜

  • Model

    • MVC์™€ ๊ฐ™๋‹ค.
  • View

    • MVC์™€ ๊ฐ™๋‹ค.
  • Controller

    • ๋ชจ๋ธ์—์„œ ๋ฐ์ดํ„ฐ๋ฅผ ๊ฒ€์ƒ‰.
    • UI๋กœ์ง ์ ์šฉ.
    • View ์ƒํƒœ ๊ด€๋ฆฌ ๋ฐ ํ‘œ์‹œ ํ•  ํ•ญ๋ชฉ ๊ฒฐ์ •.
    • View์—์„œ ์‚ฌ์šฉ์ž ์ž…๋ ฅ ํ†ต์ง€์— ๋ฐ˜์‘.

    โ€‹

ํŠน์ง•

Model-View-Presenter Class Structure

MVP๋Š” ์ปจํŠธ๋กค๋Ÿฌ์˜ ์ฑ…์ž„์— ๋ฌถ์ด์ง€ ์•Š๊ณ ๋„ ๋ทฐ์™€ ์•กํ‹ฐ๋น„ํ‹ฐ๊ฐ€ ์ž์—ฐ์Šค๋Ÿฝ๊ฒŒ ๊ฒฐํ•ฉํ•˜๋„๋ก ํ•œ๋‹ค.

  • Presenter์€ View์—์„œ ๋ถ„๋ฆฌ๋˜์–ด ์žˆ๋‹ค. View๋ฅผ interface๋ฅผ ํ†ตํ•ด ์กฐ์ž‘ํ•œ๋‹ค. ๊ทธ๋ž˜์„œ View๋ฅผ *Mockํ•˜์—ฌ ํ…Œ์ŠคํŠธํ•˜๊ธฐ ์‰ฝ๋‹ค.

  • Controller์™€ View๊ฐ€ ๋ชจ๋‘ ๋ชจ๋ธ์— ๋”ฐ๋ผ ๋‹ค๋ฅด๋‹ค.

  • Controller๋Š” ๋ฐ์ดํ„ฐ๋ฅผ ์—…๋ฐ์ดํŠธํ•œ๋‹ค.

  • View๋Š” ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ€์ ธ์˜จ๋‹ค.

    โ€‹

  • Model

    • MVC์™€ ๋™์ผํ•˜๋ฉฐ ๋ณ€ํ™”๊ฐ€ ์—†๋‹ค.
  • View

    • ๋ณ€ํ™” : ์•กํ‹ฐ๋น„ํ‹ฐ/ํ”„๋ž˜๊ทธ๋จผํŠธ๊ฐ€ ์ด์ œ ๋ทฐ์˜ ์ผ๋ถ€๋กœ ๊ฐ„์ฃผ๋œ๋‹ค๋Š” ๊ฒƒ์ด๋‹ค.

      ๋”ฐ๋ผ์„œ ์ด๋“ค์ด ์„œ๋กœ์—๊ฒŒ ์—ฐ๊ด€๋˜๋Š” ์ž์—ฐ์Šค๋Ÿฌ์šด ํ˜„์ƒ์„ ๊ทน๋ณตํ•  ํ•„์š”๊ฐ€ ์—†๋‹ค.

    • ์•กํ‹ฐ๋น„ํ‹ฐ๊ฐ€ ๋ทฐ ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ๊ตฌํ˜„ํ•ด์„œ ํ”„๋ฆฌ์  ํ„ฐ๊ฐ€ ์ฝ”๋“œ๋ฅผ ๋งŒ๋“ค ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ๊ฐ–๋„๋ก ํ•˜๋Š” ๊ฒƒ์ด ์ข‹๋‹ค.

      ํŠน์ • ๋ทฐ์™€ ๊ฒฐํ•ฉ๋˜์ง€ ์•Š๊ณ  ๊ฐ€์ƒ ๋ทฐ๋ฅผ ๊ตฌํ˜„ํ•ด์„œ ๊ฐ„๋‹จํ•œ ์œ ๋‹› ํ…Œ์ŠคํŠธ๋ฅผ ์‹คํ–‰ํ•  ์ˆ˜ ์žˆ๋‹ค.

  • Presenter

    • ๋ณธ์งˆ์ ์œผ๋กœ๋Š” MVC์˜ ์ปจํŠธ๋กค๋Ÿฌ์™€ ๊ฐ™์ง€๋งŒ, ๋ทฐ์— ์—ฐ๊ฒฐ๋˜๋Š” ๊ฒƒ์ด ์•„๋‹ˆ๋ผ ๊ทธ๋ƒฅ ์ธํ„ฐํŽ˜์ด์Šค๋ผ๋Š” ์ ์ด ๋‹ค๋ฅด๋‹ค.

      MVC๊ฐ€ ๊ฐ€์ง„ ํ…Œ์ŠคํŠธ ๊ฐ€๋Šฅ์„ฑ ๋ฌธ์ œ์™€ ํ•จ๊ป˜ ๋ชจ๋“ˆํ™”/์œ ์—ฐ์„ฑ ๋ฌธ์ œ ์—ญ์‹œ ํ•ด๊ฒฐํ•ฉ๋‹ˆ๋‹ค.

    โ€‹

*Mocking ?

  • ์ข…์†์„ฑ์— ์˜์กดํ•˜์ง€ ์•Š๊ณ  ์ฝ”๋“œ ๋‹จ์œ„๋ฅผ ํ…Œ์ŠคํŠธ ํ•  ์ˆ˜์žˆ๊ฒŒ ํ•ด์ฃผ๋Š” ํ•˜๋‚˜์˜ ํŠน์ • ๊ธฐ์ˆ ์ด๋‹ค.
  • ์ผ๋ฐ˜์ ์œผ๋กœ ๋‹ค๋ฅธ ๋ฉ”์†Œ๋“œ์™€ ์ฐจ์ด์ ์€ ์ฝ”๋“œ ์˜์กด์„ฑ์„ ๋Œ€์ฒดํ•˜๋Š” ๋ชจ์˜ ๊ฐ์ฒด(Mocking)๊ฐ€ ๊ธฐ๋Œ€์น˜๋ฅผ ์„ค์ •ํ•  ์ˆ˜ ์žˆ๋‹ค๋Š” ๊ฒƒ์ด๋‹ค. ๋ชจ์˜ ๊ฐ์ฒด(Mocking)๋Š” ์ฝ”๋“œ์— ์˜ํ•ด ํ˜ธ์ถœ๋˜๋Š” ๋ฐฉ๋ฒ•๊ณผ ์‘๋‹ตํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ์•Œ๊ฒŒ๋œ๋‹ค.

์žฅ์ 

  • ๋งค์šฐ ํ›Œ๋ฅญํ•œ ๋ถ„๋ฆฌ๋ฅผ ์ œ๊ณตํ•œ๋‹ค.

    โ€‹

๋‹จ์ 

  • ์ž‘์€ ์–ดํ”Œ or ํ”„๋กœํ†  ํƒ€์ž… ๊ฐœ๋ฐœ ์‹œ, ์˜ค๋ฒ„ ํ—ค๋“œ์ฒ˜๋Ÿผ ๋ณด์ผ ์ˆ˜ ์žˆ๋‹ค. (์‚ฌ์šฉ๋˜๋Š” ์ธํ„ฐํŽ˜์ด์Šค๊ฐ€ ๋งŽ๊ธฐ ๋•Œ๋ฌธ์—)

  • Presenter๊ฐ€ ๋ชจ๋“  ๊ฒƒ์„ ์•„๋Š” ํด๋ž˜์Šค๊ฐ€ ๋œ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ์ด๋Š” ์ฝ”๋“œ๋ฅผ ๋” ๋งŽ์ด ๋ถ„ํ•ดํ•˜๊ณ , ๋‹จ์œ„ ํ…Œ์ŠคํŠธ๊ฐ€ ๊ฐ€๋Šฅํ•œ ํด๋ž˜์Šค๋ฅผ ๋งŒ๋“ค๋ฉด ๋œ๋‹ค.

    โ€‹

์˜ˆ์ œ ์ฝ”๋“œ

public interface MainPresenter {
    void setView(MainPresenter.View view);

    void onConfirm();

    public interface View {
        void setConfirmText(String text);
    }
}
public class MainActivity extends AppCompatActivity implements MainPresenter.View{
    private MainPresenter mainPresenter;
    private Button confirmButton;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        mainPresenter = new MainPresenterTmpl(MainActivity.this);
        mainPresenter.setView(this);

        confirmButton = (Button) findViewById(R.id.btn_confirm);
        confirmButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                mainPresenter.onConfirm();
            }
        });
    }

    @Override
    public void setButtonText(String text) {
        confirmButton.setText(text);
    }
}
public class MainModel {
    public String getClickedText() {
        return "Clicked!!!";
    }
}
public class MainPresenterTmpl implements MainPresenter {
    private Activity activity;
    private MainPresenter.View view;

    public MainPresenterTmpl(Activity activity) {
        this.activity = activity;
        this.mainModel = new MainModel();
    }

    @Override
    public void setView(View view) {
        this.view = view;
    }

    @Override
    public void onConfirm() {
        if(view!=null) {
            view.setConfirmText(mainModel.getClickedText());
        }
    }
}

3. MVVM

The MVVM pattern was created to simplify the event drivenprogramming of user interfaces.

๋“ฑ์žฅ์‹œ๊ธฐ

: Activity(Fragment)๊ฐ€ View ์™€ Controller ๋‘ ๊ฐ€์ง€์˜ ํŠน์„ฑ์„ ๋ชจ๋‘ ๊ฐ€์ง€๊ณ  ์žˆ๊ธฐ ๋•Œ๋ฌธ์— View๋‚˜Controller๋ฅผ ํ•œ ์ชฝ์œผ๋กœ ๋นผ๊ฒŒ ๋  ๊ฒฝ์šฐ View์— ๋Œ€ํ•œ ๋ฐ”์ธ๋”ฉ์ด๋‚˜ ์ฒ˜๋ฆฌ์—์„œ ์ค‘๋ณต ์ฝ”๋“œ๋‚˜ ์ผ๊ด€์„ฑ์„ ์žƒ์–ด๋ฒ„๋ฆฌ๋Š” ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•  ์ˆ˜ ์žˆ๋‹ค. ์ด๋ฅผ ๊ฐœ์„ ํ•˜๊ธฐ ์œ„ํ•ด์„œ MVVM ์ด๋ž€ ํŒจํ„ด์ด ๋“ฑ์žฅํ–ˆ๋‹ค.

์ •์˜

  • Model(Data Model)
    • ๋ฐ์ดํ„ฐ ์†Œ์Šค๋ฅผ ์ถ”์ƒํ™”ํ•œ๋‹ค.
    • View Model์€ Data Model๊ณผ ํ•จ๊ป˜ ์ž‘๋™ํ•˜์—ฌ ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ€์ ธ์˜ค๊ณ  ์ €์žฅํ•œ๋‹ค.
  • View
    • ์‚ฌ์šฉ์ž์˜ ํ–‰๋™์— ๋Œ€ํ•œ ๋ทฐ ๋ชจ๋ธ์„ ์•Œ๋ฆฐ๋‹ค.
  • View Model
    • View์— ๊ด€๋ จ ๋ฐ์ดํ„ฐ์˜ ์ŠคํŠธ๋ฆผ์„ ๋…ธ์ถœํ•œ๋‹ค.

ํŠน์ง•

Model-View-View Model Class Structure

์•ˆ๋“œ๋กœ์ด๋“œ ๋ฐ์ดํ„ฐ ๋ฐ”์ธ๋”ฉ์„ ์‚ฌ์šฉํ•˜๋Š” MVVM์€ ํ…Œ์ŠคํŠธ์™€ ๋ชจ๋“ˆํ™”๊ฐ€ ์‰ฝ๊ณ  ๋ทฐ์™€ ๋ชจ๋ธ์„ ์—ฐ๊ฒฐํ•˜๊ธฐ ์œ„ํ•ด

์‚ฌ์šฉํ•ด์•ผ ํ•˜๋Š” ์—ฐ๊ฒฐ ์ฝ”๋“œ๋ฅผ ์ค„์ผ ์ˆ˜ ์žˆ๋‹ค๋Š” ์žฅ์ ์ด ์žˆ๋‹ค.

  • ViewModel์—๋Š” View์— ๋Œ€ํ•œ ์ •๋ณด๊ฐ€ ์—†๋‹ค.

    โ€‹

  • Model

    • MVC์™€ ๋™์ผํ•˜๋ฉฐ ๋ณ€ํ™”๊ฐ€ ์—†๋‹ค.
  • View

    • ๋ทฐ๋Š” ๋ทฐ๋ชจ๋ธ์— ์˜ํ•ด ๋ณด์—ฌ์ง€๋Š” ์˜ต์ €๋ฒ„๋ธ” ๋ณ€์ˆ˜์™€ ์•ก์…˜์— ์œ ์—ฐํ•˜๊ฒŒ ๋ฐ”์ธ๋”ฉ๋œ๋‹ค.
  • ViewModel

    • ๋ทฐ๋ชจ๋ธ์€ ๋ชจ๋ธ์„ ๋ž˜ํ•‘ํ•˜๊ณ  ๋ทฐ์— ํ•„์š”ํ•œ ์˜ต์ €๋ฒ„๋ธ” ๋ฐ์ดํ„ฐ๋ฅผ ์ค€๋น„ํ•œ๋‹ค.

    • ๋ทฐ๊ฐ€ ๋ชจ๋ธ์— ์ด๋ฒคํŠธ๋ฅผ ์ „๋‹ฌํ•  ์ˆ˜ ์žˆ๋„๋ก ํ›…(hook)์„ ์ค€๋น„ํ•œ๋‹ค. ๊ทธ๋Ÿฌ๋ฉด์„œ๋„ ๋ทฐ๋ชจ๋ธ์ด ๋ทฐ์— ์ข…์†๋˜์ง€๋Š” ์•Š๋Š”๋‹ค.

      โ€‹

์žฅ์ 

  • ํ…Œ์ŠคํŠธ ํ•˜๊ธฐ๊ฐ€ ์‰ฝ๋‹ค.
  • UI ์š”๊ตฌ์‚ฌํ•ญ์ด ๋‹ค์‹œ ๋ณ€๊ฒฝ๋˜๋ฉด ์‰ฝ๊ฒŒ ๋ฐ”๊ฟ€ ์ˆ˜ ์žˆ๋‹ค.

๋‹จ์ 

  • Activity์™€ Fragment์˜ ์ฝ”๋“œ๊ฐ€ ๋งŽ์•„์งˆ์ˆ˜๋ก ์œ ์ง€๋ณด์ˆ˜๊ฐ€ ์–ด๋ ต๋‹ค.

  • ์ค‘์ฒฉ๋œ ์ฝœ๋ฐฑ์ด ๋งŽ์œผ๋ฉด ์ฝ”๋“œ๋ฅผ ๋ณ€๊ฒฝํ•˜๊ฑฐ๋‚˜ ์ƒˆ๋กœ์šด ๊ธฐ๋Šฅ์„ ์ถ”๊ฐ€ํ•˜๊ธฐ ์–ด๋ ต๊ณ  ์ดํ•ดํ•˜๊ธฐ๊ฐ€ ์–ด๋ ต๋‹ค.

  • Activity์™€ Fragment์— ๋งŽ์€ ๋กœ์ง๋“ค์ด ๊ตฌํ˜„๋˜์–ด ์žˆ์–ด ์œ ๋‹› ํ…Œ์ŠคํŒ…์€ ๊ฐ€๋Šฅํ•˜์ง€๋งŒ ์–ด๋ ต๋‹ค.

    โ€‹

์˜ˆ์ œ ์ฝ”๋“œ

public class MainActivity extends AppCompatActivity {
    private MainViewModel mainViewModel;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        mainViewModel = new MainViewModel(MainActivity.this);
    }

}
public class MainModel {
    public String getClickedText() {
        return "Clicked!!!";
    }
}
public class MainViewModel {
    private Activity activity;
    private MainModel mainModel;
    private TextView textView;


    public MainViewModel(Activity activity) {
        this.activity = activity;
        this.mainModel = new MainModel();
        initView(activity);
    }

    private void initView(Activity activity) {
        textView = (TextView) activity.findViewById(R.id.btn_confirm);
        textView.setText("Non-Clicked");

        activity.findViewById(R.id.btn_confirm)
                .setOnClickListener(new View.OnClickListener() {
                    @Override
                    public void onClick(View view) {
                        String text = mainModel.getClickedText();
                        textView.setText(text);
                    }
                });
    }
}

4. ์ •๋ฆฌ