Saturday, October 24, 2020

3.8 Implement Singleton Pattern and Abstraction-Based Method

 

Implement Singleton Pattern and Abstraction-Based Method

You are collaborating with a team developing a new application for publishing short stories. In the first stage of the project, a class diagram has been created, to lay out the necessary components and the relationships between them. Now, you have received the first version of the implemented program. It has some issues that need to be resolved

Note

In this activity, you will interact with a recording of a lab made on actual devices, rather than interact with the actual devices. In this activity, when entering a command, the entire command must be entered exactly as stated, including matching the case and spaces; shortcuts and tab completion are not supported. In GUIs, you will only be able to use the menu items required for the activity. You will not be able to use other menu items.

You may navigate away from this page once you begin initializing the lab.

You will be notified once the devices are ready.

Implement Singleton Pattern and Abstraction-Based Method

As you can see in the Topology figure, to maintain the modularity of the applications you are developing, you need to put some thoughts into how components interact with each other. Many good practices have been documented in a form of design patterns. Design patterns help with simplifying future modifications of the application, and also make your code easier to understand for other developers who are familiar with the documented design patterns. There are several patterns in the toolbox that you can choose from, each solves a specific problem.

Step 1

Click Activities in the top-left corner, and then click the icon to open Visual Studio Code.

Answer

Step 2

Navigate to File > Open Folder, the folder /home/cisco/Desktop/program/ is chosen. Click v1.0, which has the first version of the program, and click OK.

Answer

Step 3

Examine the different Python modules by clicking them in the sidebar. First, click the AdminController module.

Answer

The AdminController module implements the controller for AdminView. When instantiated, it initiates a view and a new StoryModel that models the data.

Step 4

Click the AdminView module. Close the Python extension message.

Answer

The AdminView module implements the view in this architecture. It has methods for adding new stories, removing them, or listing them out. It also implements the update() method used in the observer pattern for syncing the state when there is a model change.

Step 5

Click the StoryModel module. After reviewing the first screen, click the scroll bar to see the remainder.

Answer

The StoryModel Python module is modeling the data and the actions that you can perform on that data. It also acts as a publisher in the observer pattern, so it can hold a list of subscribed objects that will be notified when a new story is added or removed.

Step 6

Click the stories Python module.

Answer

The stories model stores a couple of short stories that will be used for interaction with the program.

Step 7

Next, click the app module in the sidebar.

Answer

The app module is used to tie everything together and run the application. It instantiates the model and view and subscribes the view to the model so that it can receive state updates. As a next step, it adds a new story through the admin view, and as a last step, it lists all stories, which in this case should be one.

You will use this module for interacting with the program.

Step 8

Open the terminal from which you will run the application. In the top menu, click Terminal > New Terminal.

Answer

Step 9

Based on the earlier description of the app module, when the application runs, it should set up the observer behavior, add a new story, and then print that story from the admin view. Run the app module and see what happens. In the terminal on the bottom of the screen, type python app.py and press Enter.

Answer

There should be one story in the list, and the notification "Admin state synced!" should be displayed. It looks like the observer is not properly configured.

Step 10

Open the AdminController module again, and examine the __init__() method.

Answer

The controller creates a new fresh model object, even though the app already created a model object. The problem is that when the view component calls the controller for adding a new story, the controller uses a different model object than the app module that was created initially. A different object means different data. So, the new model object that was initiated in the controller does not have that view in the subscribers list, and there is no synchronization because of that.

Step 11

Navigate to File > Open Folder/home/cisco/Desktop/program/ is shown. Click v1.1, which has the newer version of the program, and click OK to open the newer version that implements the singleton pattern, making sure that only one StoryModel is initiated.

Answer

Step 12

From the left sidebar, open the StoryModel module in the newer version of the program.

Answer

The model now implements the singleton pattern. It exposes a public get_instance() method that another object should use when accessing it. It will make sure that only one object instance exists, solving the previous problem. Click to scroll down after reviewing the first screen.

Step 13

From the left sidebar, open the AdminController module.

Answer

Inside the constructor, the model is instantiated using the get_instance() method that will return the existing object instead of creating a new one like before.

Step 14

From the left sidebar, open the app module.

Answer

This module now also uses the get_instance() method, but in this case, because the object does not exist before this call, a new one will be created and used throughout the lifetime of the application.

Step 15

Click Terminal > New Terminal to open the terminal from which you will run the application.

Answer

Step 16

Run the app module again, now with the singleton pattern implemented, and observe the output. In the terminal on the bottom of the screen, type python app.py and press Enter.

Answer

The output shows that the AdminView, which was subscribed to the StoryModel, got notification from the model, so it synced its state.

Step 17

You have received the third iteration of the program for review. Click File > Open Folder, then choose the folder /home/cisco/Desktop/program/. Click v1.2, and click OK to open the project in Visual Studio Code.

Answer

Step 18

Open the new module UserView that implements the second view of the application, and inspect the implementation.

Answer

It is a very simple view, which allows the user to list all stories available and read a specific story. It also has a refresh() method that is used in the observer pattern process for updating the view.

Step 19

Open the app module and look at how the new view is incorporated into the previous flow.

Answer

The application now registers a new UserView with the StoryModel and subscribes this view to the notification list of the model. The story is added via the administrators view as before, and stories are listed. At the end, the UserView object is used to print the story content.

Step 20

Click Terminal > New Terminal to open the terminal.

Answer

Step 21

Run the app module from the terminal, and observe the output. In the terminal on the bottom of the screen, type python app.py and press Enter. After reviewing the first screen, click the scroll bar to see the remaining output.

Answer

After the admin state was synced, an error occurred that prevented the syncing of the model and the user view. Tracing the error output, you can conclude that the problem is the notify() method inside the StoryModel class. The notify() method calls the update() method on each of the subscribed objects. But the UserView class does not implement the update() method; it calls it refresh() instead. This problem can be solved easily. You could rename the method update(), and it should be fine. But maybe it would be better to create some sort of contract between the actors in the observer pattern, so that you are sure this will not happen when someone else subscribes a different object that also does not implement the required method.

Step 22

Navigate to File > Open Folder, then choose the folder /home/cisco/Desktop/program/. Click v1.3, and click OK to open the project folder v1.3.

Answer



Step 23

From the sidebar on the left, open the observer module.

Answer


The class Observer is an abstract class, which has the blueprint for an abstract method called update(). It does not implement the behavior; that will be the task of the classes that will rely on the abstraction—the UserView and AdminView classes.

Step 24

Inspect the UserView module.

Answer


The UserView class is now a child class of the Observer. This initiates the contract between the Observer class and the UserView, which now must implement the update() method; otherwise, it cannot be instantiated. Note however that it still has the refresh() method.

Step 25

Click Terminal > New Terminal to open the terminal.

Answer


Step 26

Run the app module, and inspect the output. In the terminal on the bottom of the screen, type python app.py and press Enter.

Answer


The error suggests that the UserView class does not implement the abstract method update(); it should, because it is the child of the Observer abstraction class and its method.

Step 27

Close the terminal. Click the refresh() method, and rename it update.

Answer



Step 28

Click File > Save to save the file.

Step 29

Open the StoryModel. After reviewing the first screen, click the scroll bar to see the next part of the output. Then click the scroll bar to go back up.

Answer


The StoryModel changed slightly to accommodate the contract with the Observer class. It imports the Observer class and uses it in the subscribe() method. It is used for checking whether the object that wants to subscribe to the model inherits the Observer class. If it does not, then it cannot be put into the observers list. This way, the abstraction contract is fulfilled from both the observer and observable side.

Step 30

Click Terminal > New Terminal to open the terminal.

Answer


Step 31

Run the app module again in the terminal, and inspect the output. In the terminal on the bottom of the screen, type python app.py and press Enter.

Answer


Now, you can see that the UserView was updated properly, but the AdminView was not. Even though it implements the update() method, it does not rely on the Observer abstraction, so the StoryModel did not allow the user to subscribe.

Step 32

Open the AdminView module from the sidebar, close the terminal, and import the Observer class. To do so, click the second row just beneath from AdminController import AdminController. In the input box, type from observer import Observer and press Enter.

Answer



Step 33

Make the AdminView a child class of the Observer abstraction. To do so, click the class AdminView:. In the input box, type (Observer) and press Enter.

Answer


Step 34

Click File > Save to save the file.

Step 35

Click Terminal > New Terminal to open the terminal.

Step 36

Run the application again from the terminal, and observe the result. In the terminal on the bottom of the screen, type python app.py and press Enter.

Answer


As you can see, both views are updated correctly by implementing the Observer pattern correctly.

No comments:

Post a Comment