- Mastering Windows Presentation Foundation
- Sheridan Yuen
- 926字
- 2021-06-24 16:49:06
Providing services
The job of the base classes and interfaces in our application framework are to encapsulate functionality that is commonly used by our View Models and Data Models. When the required functionality is more complex, or when it involves particular resources, or external connections, we implement it in separate service, or manager classes. For the remainder of this book, we will refer to these as manager classes. In larger applications, these are typically provided in a separate project.
Encapsulating them in a separate project enables us to reuse the functionality from these classes in our other applications. Which classes we use in this project will depend on the requirements of the application that we're building, but it will often include classes that provide the ability to send emails, to access the end user's hard drive, to export data in various formats, or to manage global application state for example.
We will investigate a number of these classes in this book, so that we have a good idea of how to implement our own custom manager classes. The most commonly used of these classes can normally be accessed directly from the base View Model class via properties. There are a few different ways that we can expose these classes to the View Models, so let's examine them.
When a manager class is used often, and for short durations each time, we can expose a new instance of them each time, as follows:
public FeedbackManager FeedbackManager { get { return new FeedbackManager(); } }
However, if a manager class is required for the life of the application because it must remember a particular state or configuration, for example, then we typically use the static keyword in one way or another. The simplest option would be to declare a normal class, but expose it via a static property:
private static StateManager stateManager = new StateManager(); ... public static StateManager StateManager { get { return stateManager; } }
An alternative method of having one and only one instance of a class being instantiated and having it stay alive for as long as the application is running is for us to use the Singleton pattern. While it was all the rage twenty or so years ago, it has unfortunately recently fallen foul of more modern programming principles, such as the likes of SOLID, which states that each class should have a single responsibility.
The Singleton pattern breaks this principle as it serves whatever purpose we design it for, but it is also responsible for instantiating itself and maintaining a single access point. Before discussing the merits and pitfalls of this pattern further, let's take a look at how we might implement it in our manager class:
namespace CompanyName.ApplicationName.Managers { public class StateManager { private static StateManager instance; private StateManager() { } public static StateManager Instance { get { return instance ?? (instance = new StateManager()); } } ... } }
Note that it can be implemented in a variety of ways, but this particular way uses lazy initialization, where the instance is not instantiated until it is first referenced via the Instance property. Using the ?? operator again, the Instance property getter can be read as "return the one and only instantiated instance if it is not null, or, if it is, instantiate the one and only instance and then return it." The significant part of this pattern is that as there is no public constructor and, therefore, the class cannot be externally instantiated, this property is the sinlgle way to access the internal object.
However, this is the very part that causes trouble for some developers, as this makes inheritance impossible with these classes. In our case though, we won't need to extend our StateManager class, so that is not a concern for us. Others may point to the problem that exposing this Singleton class, as shown in the following code, will tightly couple it to the base View Model class that it is declared in:
public StateManager StateManager { get { return StateManager.Instance; } }
While this is true, what harm is that with this class? Its purpose is to maintain the state of user settings, common or default values, and values for UI display and operation statuses. It contains no resources and no real reason to avoid using it when running unit tests, so in this case, the tight coupling is inconsequential. In this regard, the Singleton pattern continues to be a useful tool in the right situations, but we should certainly be aware of its pitfalls all the same.
However, if a particular manger class does utilize resources or creates some form of connection with the outside world, for example, like an EmailManager would, then we will need to create an interface for it to maintain our Separation of Concerns. Remember that interfaces enable us to disconnect the actual application components and replace them with mock components while testing. In these cases, we have to expose the functionality in the base classes slightly differently:
private IEmailManager emailManager; ... public BaseViewModel(IEmailManager emailManager) { this.emailManager = emailManager; } } ... public IEmailManager EmailManager { get { return emailManager; } }
The general idea here is for us to have no direct contact with the manager class in hand, instead accessing its functionality through the interface methods and properties. By doing this, we are able to decouple the manager class from the View Models that use it and therefore enable them to be used independently of each other. Note that this is a very simple example of Dependency Injection.
- Learning Linux Binary Analysis
- Learning Laravel 4 Application Development
- Python數(shù)據(jù)可視化之Matplotlib與Pyecharts實戰(zhàn)
- Learning Network Forensics
- Visual C++開發(fā)入行真功夫
- Natural Language Processing with Python Quick Start Guide
- C++ System Programming Cookbook
- 深入淺出Python數(shù)據(jù)分析
- Splunk Essentials
- Visual FoxPro數(shù)據(jù)庫程序設(shè)計
- JSP大學(xué)實用教程
- Implementing NetScaler VPX?(Second Edition)
- Instant OpenCV for iOS
- App Inventor開發(fā)實戰(zhàn)
- 天天學(xué)敏捷:Scrum團(tuán)隊轉(zhuǎn)型記