Interpreter Pattern
The Interpreter pattern is designed to evaluate language grammar or expressions. It provides a way to define a grammar representation and an interpreter that uses this representation to interpret sentences in the language.
Core Components
The pattern consists of four main components:
- Abstract Expression: Defines the interface for interpreting operations
- Terminal Expression: Implements interpretation for terminal symbols in the grammar
- Non-terminal Expression: Implements interpretation for non-terminal symbols
- Context: Contains global information for the interpretation process
Implementation Example
Let's create a simple translation system using the Interpreter pattern:
interface TranslationProcessor {
String processTranslation(String input);
}
class GoogleTranslator implements TranslationProcessor {
private final String targetPhrase = "Hello world";
@Override
public String processTranslation(String input) {
if (targetPhrase.equals(input)) {
return "Google: Hola mundo";
}
return "No translation available";
}
}
class BingTranslator implements TranslationProcessor {
private final String targetPhrase = "Hello world";
@Override
public String processTranslation(String input) {
if (targetPhrase.equals(input)) {
return "Bing: Bonjour le monde";
}
return "No translation available";
}
}
class DeepLTranslator implements TranslationProcessor {
private final String targetPhrase = "Hello world";
@Override
public String processTranslation(String input) {
if (targetPhrase.equals(input)) {
return "DeepL: Ciao mondo";
}
return "No translation available";
}
}
public class TranslationDemo {
public static void main(String[] args) {
String phraseToTranslate = "Hello world";
TranslationProcessor google = new GoogleTranslator();
TranslationProcessor bing = new BingTranslator();
TranslationProcessor deepL = new DeepLTranslator();
System.out.println(google.processTranslation(phraseToTranslate));
System.out.println(bing.processTranslation(phraseToTranslate));
System.out.println(deepL.processTranslation(phraseToTranslate));
}
}
Output:
Google: Hola mundo
Bing: Bonjour le monde
DeepL: Ciao mondo
Adavntages and Disadvantages
Benefits:
- Easy to extend with new expression types
- Simple implementation for basic grammars
Drawbacks:
- Limited practical applications
- Can lead to excessive number of classes
- Difficult to maintain when complexity increases
Use Cases
- SQL parsing engines
- Mathematical expression evaluators
- Regular expression processors
- Domain-specific language interpreters
Iterator Pattern
The Iterator pattern provides a way to access elements of a collection sequentially without exposing the underlying structure. It separates traversal concerns from the collection itself.
Core Components
- Iteraotr Interface: Declares methods for accessing and traversing elements
- Concrete Iterator: Implements the iterator interface
- Aggregate Interface: Provides method to create iterators
- Concrete Aggregate: Implements the aggregate interface
Implementation Example
Creating a custom iterator for a collection:
interface CollectionIterator {
boolean hasMoreElements();
Object getNextElement();
}
interface DataCollection {
CollectionIterator createIterator();
void addItem(Object item);
Object retrieveItem(int position);
}
Concrete implementations:
import java.util.ArrayList;
import java.util.List;
class ItemContainer implements DataCollection {
private List<object> items = new ArrayList<>();
@Override
public CollectionIterator createIterator() {
return new ItemIterator();
}
@Override
public void addItem(Object item) {
items.add(item);
}
@Override
public Object retrieveItem(int position) {
return items.get(position);
}
class ItemIterator implements CollectionIterator {
private int currentPosition = 0;
@Override
public boolean hasMoreElements() {
return currentPosition < items.size();
}
@Override
public Object getNextElement() {
if (hasMoreElements()) {
return items.get(currentPosition++);
}
return null;
}
}
}
</object>
Testing the implementation:
public class IteratorDemo {
public static void main(String[] args) {
DataCollection container = new ItemContainer();
container.addItem("apple");
container.addItem("banana");
container.addItem("cherry");
container.addItem("date");
CollectionIterator iterator = container.createIterator();
while (iterator.hasMoreElements()) {
Object item = iterator.getNextElement();
System.out.println("Item: " + item);
}
}
}
Output:
Item: apple
Item: banana
Item: cherry
Item: date
Advantages and Disadvantages
Benefits:
- Provides uniform interface for different collections
- Supports multiple traversal strategies
- Encapsulates traversal logic
Drawbacks:
- Increases system complexity with additional classes
- May impact performance due to abstraction overhead
- Can be overkill for simple iteration needs
Use Cases
- Traversing complex data structures
- Providing different ways to iterate over collections
- Implementing custom traversal algorithms
- Creating uniform interfaces for heterogeneous collections