Creational Patterns ( ์ƒ์„ฑ ํŒจํ„ด )

These design patterns provides way to create objects while hiding the creation logic, rather than instantiating objects directly using new operator. This gives program more flexibility in deciding which objects need to be created for a given use case. 

์ƒ์„ฑํŒจํ„ด์€ ๊ฐ์ฒด์˜ ์ƒ์„ฑ๋กœ์ง์„ ์ˆจ๊ธฐ๊ณ  new ๋ช…๋ น์–ด๋ฅผ ํ†ตํ•˜์ง€ ์•Š๊ณ  ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•˜๋Š” ๋ฐฉ๋ฒ•๋“ค์„ ์ œ๊ณตํ•œ๋‹ค. ์ด๋Š” ํŠน์ • ์ƒํ™ฉ์—์„œ ์–ด๋–ค ๋ฐฉ๋ฒ•์œผ๋กœ ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•ด์•ผํ• ์ง€๋ฅผ ๊ฒฐ์ •ํ•˜๋Š”๋ฐ ์žˆ์–ด์„œ ์œ ์—ฐ์„ฑ์„ ์ œ๊ณตํ•œ๋‹ค. 


 Structural Patterns ( ๊ตฌ์กฐ์  ํŒจํ„ด )

These design patterns concern class and object composition. Concept of inheritance is used to compose interfaces and define ways to compose objects to obtain new functionalities. 

๊ตฌ์กฐ์  ํŒจํ„ด๋“ค์€ ํด๋ž˜์Šค์™€ ๊ฐ์ฒด์˜ ๊ตฌ์„ฑ์— ๊ด€์—ฌํ•œ๋‹ค.

 

 Behavioral Patterns ( ํ–‰์œ„์  ํŒจํ„ด )

These design patterns are specifically concerned with communication between objects.

์ด ํŒจํ„ด๋“ค์€ ๊ฐ์ฒด๋“ค ์‚ฌ์ด์˜ ์ปค๋ฎค๋‹ˆ์ผ€์ด์…˜์— ๊ด€์‹ฌ์„ ๊ฐ€์ง„๋‹ค.

 

์˜ค๋Š˜ ์‚ดํŽด๋ณผ  Interpreter ํŒจํ„ด์€ Behavioral ํŒจํ„ด์— ์†ํ•ฉ๋‹ˆ๋‹ค. 

 

Interpreter Pattern Structure

 



  

ํŒจํ„ด์˜ ๋ชฉ์  ( Intent ) :  

Given a language, define a represention for its grammar along with an interpreter that uses the representation to interpret sentences in the language.


ํŒจํ„ด์ด ๋‚˜์˜ค๊ฒŒ ๋œ ๋™๊ธฐ ( Motivation ) :

   
A class of problems occurs repeatedly in a well-defined and well-understood domain. If the domain were characterized with a "language", then problems could be easily solved with an interpretation "engine".

 

GoF์˜ ๋””์ž์ธ ํŒจํ„ด์—์„œ๋Š” ์•„๋ž˜์™€ ๊ฐ™์€ ์˜ˆ์ œ๊ฐ€ ๋‚˜์˜ต๋‹ˆ๋‹ค.

 

์•„๋ž˜ ๋ฌธ๋ฒ•์ด ์ •๊ทœ์‹์„ ํ‘œํ˜„ํ•œ๋‹ค๊ณ  ๊ฐ€์ •ํ•ฉ๋‹ˆ๋‹ค.

expression ::= literal | alternation | sequence | repetition |
                   '(' expression ')'

alternation ::= expression '|' expression
sequence ::= expression '&' expression
repetition ::= expression '*'
literal ::= 'a' | 'b' | 'c' | ... { 'a' | 'b' | 'c' | ... }*  


์—ฌ๊ธฐ์„œ expression์€ ์‹œ์ž‘ symbol์ด๊ณ  literal์€ ์ข…๋ฃŒ symbol์ž…๋‹ˆ๋‹ค. 

์ธํ„ฐํ”„๋ฆฌํ„ฐ ํŒจํ„ด์€ ๊ฐ ๋ฌธ๋ฒ•์„ ํ‘œํ˜„ํ•˜๊ธฐ ์œ„ํ•ด์„œ ํ•˜๋‚˜์˜ ํด๋ž˜์Šค๋ฅผ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค. ์šฐ์ธก์˜ ์‹ฌ๋ณผ๋“ค์€ ์ด ํด๋ž˜์Šค๋“ค์˜ ์ธ์Šคํ„ด์Šค์ž…๋‹ˆ๋‹ค. ์œ„ ๋ฌธ๋ฒ•์€ ๋‹ค์„ฏ๊ฐœ์˜ ํด๋ž˜์Šค๋กœ ์ด๋ฃจ์–ด์ ธ ์žˆ์Šต๋‹ˆ๋‹ค. ์ถ”์ƒํด๋ž˜์Šค RegularExpression ๊ณผ ๊ทธ ํ•˜์œ„ ํด๋ž˜์Šค๋“ค์ธ LiteralExpression, AlternationExpression, SequenceExpression, ๊ทธ๋ฆฌ๊ณ  RepetitionExpression์ž…๋‹ˆ๋‹ค. ๋งˆ์ง€๋ง‰์˜ ์„ธ ํด๋ž˜์Šค๋“ค์€ ํ•˜์œ„ํ‘œํ˜„์‹์„ ๊ฐ–๋Š” ๋ณ€์ˆ˜๋ฅผ ์ •์˜ํ•ฉ๋‹ˆ๋‹ค.


 

์ด ๋ฌธ๋ฒ•์œผ๋กœ ์ •์˜๋œ ๋ชจ๋“  ์ •๊ทœ ํ‘œํ˜„์‹์€ ์œ„์™€๊ฐ™์€ ํด๋ž˜์Šค ์ธ์Šคํ„ด์Šค๋กœ ์ด๋ฃจ์–ด์ง„ ์ถ”์ƒ ๋ฌธ๋ฒ• ํŠธ๋ฆฌ๋กœ ํ‘œํ˜„๋ฉ๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค๋ฉด, ์ถ”์ƒ ๋ฌธ๋ฒ• ํŠธ๋ฆฌ๋Š” ์•„๋ž˜์™€ ๊ฐ™์Šต๋‹ˆ๋‹ค.


 

represents the regular expression  

raining & (dogs | cats) *

We can create an interpreter for these regular expressions by definingthe Interpret operation on each subclass of RegularExpression.Interpret takes as an argument the context in which to interpret theexpression. The context contains the input string and information onhow much of it has been matched so far. Each subclass ofRegularExpression implements Interpret to match the next part of theinput string based on the current context. For example,

  • LiteralExpression will check if the input matches the literal it defines,

  • AlternationExpression will check if the input matches any of its alternatives,

  • RepetitionExpression will check if the input has multiple copies of expression it repeats, and so on.

 

์œ ์šฉ์„ฑ ( Applicability ) :

 

Use the Interpreter pattern when there is a language to interpret, and you can represent statements in the language as abstract syntax trees.The Interpreter pattern works best when

 

  • the grammar is simple. For complex grammars, the class hierarchy forthe grammar becomes large and unmanageable. Tools such as parsergenerators are a better alternative in such cases. They can interpret expressions without building abstract syntax trees, which can savespace and possibly time.

  • efficiency is not a critical concern. The most efficient interpreters are usually not implemented by interpreting parse trees directly but by first translating them into another form. For example, regular expressions are often transformed into state machines. But even then,the translator can be implemented by the Interpreter pattern, so the pattern is still applicable.

๋“ฑ์žฅ ์ธ๋ฌผ ( Participants ) :

  • AbstractExpression (RegularExpression)
    o
    declaresanabstractInterpretoperationthatiscommontoallnodes in the abstract syntax tree.
  • TerminalExpression (LiteralExpression)
    o
    implements an Interpret operation associated with terminal symbols in the grammar.
    o
    an instance is required for every terminal symbol in a sentence.

  • NonterminalExpression (AlternationExpression,RepetitionExpression, SequenceExpressions)
    o
    one such class is required for every rule R ::= R1 R2 ... Rn in the grammar.
    o
    maintains instance variables of type AbstractExpression for each of the symbols R1 through Rn.
    o
    implements an Interpret operation for nonterminal symbols in the grammar. Interpret typically calls itself recursively on the variables representing R1 through Rn.

  • Context
    o
    contains information that's global to the interpreter.

  • Client
    o
    builds (or is given) an abstract syntax tree representing a particular sentence in the language that the grammar defines. The abstract syntax tree is assembled from instances of the NonterminalExpression and TerminalExpression classes.
    o
    invokes the Interpret operation.


์›๋ฆฌ ( Collaborations ) :  

  • The client builds (or is given) the sentence as an abstract syntax tree of NonterminalExpression and TerminalExpression instances. Then the client initializes the context and invokes the Interpret operation.

  • Each NonterminalExpression node defines Interpret in terms ofInterpret on each subexpression. The Interpret operation of eachTerminalExpression defines the base case in the recursion.

  • The Interpret operations at each node use the context to store and access the state of the interpreter.

ํŒจํ„ด ์‚ฌ์šฉ๋ฒ•

  1. Decide if a "little language" offers a justifiable return on investment.
  2. Define a grammar for the language.
  3. Map each production in the grammar to a class.
  4. Organize the suite of classes into the structure of the Composite pattern.
  5. Define an interpret(Context) method in the Composite hierarchy.
  6. The Context object encapsulates the current state of the input and output as the former is parsed and the latter is accumulated. It is manipulated by each grammar class as the "interpreting" process transforms the input into the output.
ํŒจํ„ด ์‚ฌ์šฉ์˜ ์žฅ๋‹จ์  ( Consequences ): 

  1. The Interpreter pattern has the following benefits and liabilities:  


  2. 1. It's easy to change and extend the grammar. Because the pattern uses classes to represent grammar rules, you canuse inheritance to change or extend the grammar. Existing expressions can be modified incrementally, and new expressions can be defined as variations on old ones.  


  3. 2. Implementing the grammar is easy,too. Classes defining nodes in the abstract syntax tree have similar implementations. These classes are easy to write, and often their generation can be automated with a compiler or parser generator.  


  4. 3. Complex grammars are hard to maintain. The Interpreter pattern defines at least one class for every rule in the grammar (grammar rules defined using BNF may require multiple classes). Hence grammars containing many rules can be hard to manage and maintain. Other design patterns can be applied to mitigate the problem (see Implementation).But when the grammar is very complex, other techniques such as parser or compiler generators are more appropriate.  


  5. 4. Adding new ways to interpret expressions. The Interpreter pattern makes it easier to evaluate an expression in a new way. For example, you can support pretty printing ortype-checking an expression by defining a new operation on the expression classes. If you keep creating new ways of interpreting an expression, then consider using the Visitor pattern to avoid changing the grammar classes.

 

๊ด€๋ จ ํŒจํ„ด๋“ค :  

 

Composite :The abstract syntax tree is an instance of the Composite pattern.

Flyweight shows how to share terminal symbols within the abstract syntax tree.

Iterator :The interpreter can use an Iterator to traverse the structure.

Visitor can be used to maintain the behavior in each node in the abstract syntax tree in one class.

 

์ถ”๊ฐ€ ์ •๋ณด :    
  • Considered in its most general form (i.e. an operation distributed over a class hierarchy based on the Composite pattern), nearly every use of the Composite pattern will also contain the Interpreter pattern. But the Interpreter pattern should be reserved for those cases in which you want to think of this class hierarchy as defining a language.
  • Interpreter can use State to define parsing contexts.
  • The abstract syntax tree of Interpreter is a Composite (therefore Iterator and Visitor are also applicable).
  • Terminal symbols within Interpreter's abstract syntax tree can be shared with Flyweight.
  • The pattern doesn't address parsing. When the grammar is very complex, other techniques (such as a parser) are more appropriate.
 

์ถœ์ฒ˜ :  http://sourcemaking.com/design_patterns/interpreter

Design Patterns : Element of Reusable Object Oriented Software ( by GoF, 1994 )