This is the serial of the design pattern question and answer 1. In this series, we will cover the interpreter, iterator, mediator, memo, and observer patterns.
If you have not read my previous series, you can always start from below
- Design Pattern Quiz 1: Factory mode, abstract Factory mode, constructor mode, prototype mode, singleton mode, Command mode
- Design mode Quiz 3: state mode, policy mode, visitor mode, adapter mode, enjoy meta mode
- Design mode Quiz 4: Bridging mode, combo mode, decorator mode, appearance mode, responsibility chain mode (COR), proxy mode, template mode
- UML FAQ 1:UML Part 1
- UML FAQ 2:UML Part 2
What is the interpreter mode?
The interpreter pattern allows us to interpret the syntax as a code solution. Okay, what does that mean? The syntax is mapped to the class and the solution is formed. As an example, 7–2 can be mapped to the "Clsminus" class. In a word, the interpreter pattern provides us with a solution that guides how to write an interpreter that parses the syntax and executes the code. Here is a simple example of an interpreter that can interpret the date as the corresponding code and enter the correct result in accordance with the date format syntax we provide.
Date syntax
Let's start with the interpreter for the date format shown in the figure "Date syntax". Before we begin, we need to understand the different components in the interpreter pattern before we handle the mappings. The context part contains the data, and the logical part contains the transformation logic that transforms the data in the context into a readable format.
Context and logic
Let's look at how the syntax for the date format is defined. The first step in defining any syntax is to break the syntax down into small logical components. The graph "syntax mapping and class mapping" shows how to identify these components and how to map them to logical classes that handle this part of the syntax. We've broken the date format into 4 components, the month, day, year, and delimiter, respectively. For these 4 components, we will define the classes that contain the logic shown in the diagram, respectively. We will then create different classes for different components of the date format.
Mapping of syntax mappings to classes
As I said earlier, there are two kinds, one is an expression class that contains logic, and the other is a context class that contains data, as shown in expressions and context classes. We define the expression parsing algorithms in different classes, which derive from the common interface "clsabstractexpression" and implement the "Evaluate" method. The "Evaluate" method receives the context class that contains the data as a parameter, and it parses the data according to the expression logic. The "clsyearexpression" instance replaces "YYYY" with the year value, and "Clsmonthexpression" replaces "MM" with the month value, and so on.
Interpreter class Diagram
Expressions and Context Classes
Now that we have a separate parsing logic class for expressions, let's see how the client will use this logic. The client first passes the date syntax format to the context class. Depending on the date format, we add an expression instance to the collection in turn. If we find "DD", we add a "clsdayexpression" instance; if we find "MM", we add a "clsmonthexpression" instance, and so on. Finally, we only need to iterate through the collection and invoke the "Evaluate" function. After all the "Evaluate" functions have been executed, we will display the results.
Client interpreter Logic
can you explain the iterator pattern?
The iterator pattern allows sequential access to each element without exposing the internal code implementation. Let's take a look at that. Suppose you have a collection of records, you need to traverse each record sequentially, and you need to keep the current access location, then you need the iterator pattern. This is the most common design pattern and you will unknowingly use it. To some extent, when you use "foreach" (which allows us to access a collection individually, by Element), you are already using the iterator pattern.
Iterator business logic
In the diagram "Iterator business logic", we use the "Clsiterator" class to hold a collection of customer classes. Inside the "Clsiterator" class, we define an array, and a method called "Fillobjects", which is used to load the contents of an array. The customer collection array is private and the customer's data can be accessed by the array's subscript. So we define a set of public functions that contain "Getbyindex" (accessed by specifying the table below), "Prev" (get the previous customer data in the collection), "Next" (Get the next customer data in the collection), "GetFirst" (get the first customer data in the collection), " GetLast "(Gets the last customer data in the collection).
We expose these functions only to clients. These functions iterate through the collection in a careful order and are able to memorize the current traversed index.
The following figure, "Customer traversal logic," shows how to use the instance "Objiterator" of the Class "Clsiterator" to display the next, previous, last, first, and customer data by index.
Customer Traversal logic
can you explain the mediator pattern?
Most of the time, communication between components in a project is complex. Therefore, the logical relationship between components becomes extremely complex. The mediator pattern helps to minimize complexity by communicating between objects in a non-interrelated way.
Example of a mediator pattern
Let's consider the figure "Mediator pattern Example", which describes a real-world scenario where the mediator pattern needs to be used. It is a very user-friendly interface. It has 3 typical scenes.
Scenario 1: When the user enters the text box, the Add and clear buttons should be available. Once you have no text in the text box, you should disable the Add and clear buttons.
Scenario 1
Scenario 2: When the user clicks the Add button, the data in the text box should be entered in the list box. Once the data is entered into the list box, it should empty the contents of the text box and disable the Add and clear buttons.
Scenario 2
Scene 3:-When the user taps the Clear button, the contents of the FirstName text box are emptied and the add and clear buttons are disabled.
Scenario 3
Now, from the interface, we can infer how complex the interaction between these interfaces is. "Complex interactions between components" shows logical complexity.
Complex interactions between components
Well, let me show you a nice picture of "simplifying through mediators". Rather than communicating directly with its components, the mediator component manages messages sent to other components through a central component that acts as a mediator, which is more elegant and clear.
Simplified by mediators
Now let's see what the code looks like. We will use C #, but you can easily apply this idea to Java or other languages. The "mediator class" shows a complete code overview of a mediator class.
The first thing the Mediator class does is to save a reference to a class that has complex communications. As a result, we have exposed 3 overloaded methods "Register" externally. The "Register" method receives the text box object and the button object as a parameter. The interaction scenario focuses on the "Clickaddbutton", "TextChange" and "Clickclearbutton" three methods. Depending on the scenario, these methods will manage the availability and disabling of UI components.
Mediator class
The current customer logic is very elegant and very cool. In the constructor, we first register all components involved in complex communication with the Mediator object. Then in each scenario, we only need to invoke the function of the Mediator object. Simply put, when there is a change in text, we invoke the "TextChange" function of the mediator object, and when the user clicks the Add button, we call "Clickaddbutton", and when the Clear button is clicked, the "Clickclearbutton" function is called.
Customer logic for the mediator model
can you explain the memo pattern?
Memo mode can get the internal state of an object without destroying the encapsulation principle. Memo mode helps us to store a snapshot of an object that can be recovered at any time. Let's take an example to understand. Consider the figure "Memo sample", which shows a customer's interface. Suppose the user starts editing a customer record and makes some changes. Then the user feels there is an error and wants to be able to revert to the original data. This is where the memo pattern comes in. It helps us to store a backup of the data, and when the user taps the Cancel button, the object can revert to its original state.
Memo Example
Let's try to use C # to implement the customer interface that we just talked about. Is the customer class "Clscustomer", which aggregates a memo class "Clscustomermemento". The memo class will hold a snapshot of the data, which is the exact copy of the customer class "Clscustomer" (except for the method). When the customer class "Clscustomer" is initialized, the memo class is also initialized. When the customer class data changes, the snapshot of the memo class does not change. The "Revert" function writes the data of the memo back to the main class.
Memorandum of the customer category
The client's code is fairly straightforward. We create a customer class. Once a problem is encountered, we click the "Cancel" button and call the "Revert" function to restore the modified data to the original data of the memo snapshot. The figure "Memo client code" vividly shows the process.
Memo Client Code
can you explain the observer pattern?
The observer pattern helps us communicate with the parent class, the association class, or the dependent class. In the observer pattern, there are two important concepts, namely "subject" and "observer". The principal sends a notification that the observer will be notified if the Observer has already registered with the subject. The subject and observer shows how the application (Principal) sends notifications to all observers (mail, event log, Short message service). You can map This example to the Publisher and Subscriber model. The publisher is the application, and the Subscriber is the message, the event log, and the short message service.
Subject and Observer
Let's try to encode the example defined earlier. Let's start by looking at the Subscriber/Notifier class. The figure "Subscriber class" makes a visual presentation. For all subscribers, we have a common interface, "Inotification", which has a "notify" method. All classes that need to receive notifications need to implement this "Inotification" interface. All classes that need to receive notifications define their own response methods. For the current scenario, we only print a message indicating that a particular notification was executed.
Subscribers ' classes
As I said earlier, there are two parts in the observer pattern, one is the observer/Subscriber we said earlier, the other is the publisher, or the principal.
The publisher has a list of all the collections of subscribers who are interested in receiving notifications. With "AddNotification" and "removenotification", we can add or remove subscribers from the list. The "Notifyall" method iterates through all subscribers and sends a notification.
Publisher class, Principal class
Now we have the Publisher and Subscriber classes. Let's do a bit of writing the client code. The following is the code snippet for the Observer mode client. First we create a Notifier object that has a collection of subscribers. We then add the subscribers to the collection who need to be notified.
Now, if a client enters a customer code that exceeds 10 characters, it needs to notify all subscribers.
Observer mode client code
If you have not studied design patterns or do not want to fully read this article, please watch our free video design mode training and quiz.
License
This article, along with the associated code and files, is licensed through the Code Project Open License (CPOL) protocol.
Original link: CodeProject translation: Importnew.com-shenggordon
Link: http://www.importnew.com/14347.html
(ii) Design pattern question and Answer 2