๐ป Programming/GoF Design Pattern
[๋์์ธํจํด] ์ธํฐํ๋ฆฌํฐ ํจํด ( Interpreter Pattern )
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.
ํจํด ์ฌ์ฉ๋ฒ
- Decide if a "little language" offers a justifiable return on investment.
- Define a grammar for the language.
- Map each production in the grammar to a class.
- Organize the suite of classes into the structure of the Composite pattern.
- Define an
interpret(Context)
method in the Composite hierarchy. - 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.
-
The Interpreter pattern has the following benefits and liabilities:
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.
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.
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.
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 )
'๐ป Programming > GoF Design Pattern' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
[๋์์ธํจํด] ๋ฉ๋ฉํ ํจํด ( Memento Pattern ) (0) | 2015.11.03 |
---|---|
[๋์์ธํจํด] ๊ด์ฐฐ์(์ต์ ๋ฒ) ํจํด ( Observer Pattern ) (0) | 2015.11.03 |
[๋์์ธํจํด] ์ค์ฌ์ ํจํด ( Mediator Pattern ) (0) | 2015.11.03 |
[๋์์ธํจํด] ๋ฐ๋ณต์(์ดํฐ๋ ์ดํฐ) ํจํด ( Iterator Pattern ) (0) | 2015.11.03 |
[๋์์ธํจํด] ์ปค๋งจ๋ ํจํด ( Command Pattern ) (0) | 2015.11.03 |