. NET Architecture Design Guide for beginners (iii) Design Mode

Source: Internet
Author: User

 

In the previous article, we initially learned about the OO design. The most unique feature of the OO design is the way he views the needs. In this way, we do not need to rush to determine which processes the software needs to implement, which functional points should be designed, and which pictures should be made. Instead, we need to focus on some more basic concepts in the requirements. First, develop some parts based on these concepts, and then assemble these parts to implement the required functions. In this way, we don't need to know all the business needs from the very beginning. We just need to know some important requirements to start development. The program developed in this way not only meets the current needs, but also serves as a platform for business development. On this platform, new functions can be continuously developed.

There are many practical examples of this design concept, such as Microsoft Office. The following figure shows the basic objects in Excel:

Excel functions are built on this object model. For example, to set the font, you can write it as follows: First open a font dialog box, select the font and font size, and then set the font to the Area:

 

Font font = CommonFontDialog. ChooseFont ();
Application. ActiveWorkbook. ActiveSheet. Range ("A1"). Font = font;

Excel also exposes the references of these objects to the script engine, so we can use VBA to call them and implement the various functions we want. This is the Office macro. We can write a VB script, copy the cells in the area selected by the mouse to another worksheet, and assign the values of a cell to a formula to calculate the required values. Excel is not only a handy tabulation tool, but also a powerful and easy-to-use development platform. Users can develop required functions at any time based on their own ideas. Some large software systems have such characteristics. It is impossible to clarify all functional requirements from the very beginning. What is important is to form a business development platform and provide some business programming interfaces, on this platform, new functions can be continuously developed. This development method is hard to implement without OO design.

The first maintainer and first user of the software are the developer himself. Therefore, rapid development, flexible functions, and simple maintenance-these features are often shared in well-designed software.

When we use the OO method to design a program, we will encounter the following difficulties: we have found some vague concepts from the needs, but how can we establish a rational object model based on these concepts, which concepts should be a class, which should be a method and a property, and what is the relationship between these classes? The most fundamental way to solve this problem is, of course, to have a thorough understanding of the needs (for example, flip the accounting principles to see how receivables are recorded when they are not received or already received, one accounting principle may be an important object. It helps users make a power supply scheme, draw a sketch, or a calculation formula is an important object ). After solving the difficulties, some people sum up experience and form some fixed routines to solve specific problems. Such routines are the design model.

Some design patterns have no inevitable relationship with OO, such as hierarchical patterns and message patterns. However, most design patterns are formed in the OO design. These patterns can help us to discover the relationships between objects in the system and design objects. Understanding these patterns can help us make software designs more rational. In addition, in the process of exploring the needs, we can also get some inspiration from the model, get the design inspiration, and discover the real face of the demand.

In the previous article, we saw the charge type: charge, which is actually a simple design mode: Composite ). The structure of this class is as follows:

The charge type is an aggregation of its own. You can use the GetChildren method to get other charges included in a certain Fee. If a fee does not include any other fee, the amount is determined by himself; otherwise, it is determined by the sum of the included fees, the two situations provide the same method for the outside world: GetValue. In this way, when we want to display a bill fee, we do not have to judge whether it contains other fees, and it is much easier to call. The combination mode reflects the hierarchical inclusion of bills and expenses.

In the case above, both the aggregation class and the element class are of the same type. In some cases, they belong to different types. For example, an enterprise's marketing network is composed of the following elements: Company, marketing department, direct sales store, agent, free agent, and salesperson. As follows:

The company has established multiple marketing departments according to the administrative region. The Marketing Department has established its own direct-sale stores, and also cooperates with many agents and independent agents. The direct-sale stores and agents employ salesclerks. Every day, the company needs to query and analyze the situation of each sales outlet. It needs to know how many orders they have placed, how much money they have received, and how many new customers they have developed.

This is a complex structure. There are many outlet types, their sales methods vary greatly, and their statistical methods vary. In addition, you need to add the number of subordinate outlets and the number of subordinate outlets when calculating some values. If the combination mode is used, this problem can be solved.

We can design a class called SaleUnit ). This class is an aggregation of its own, and can be accessed by a set member to its subordinate unit. And each of his subordinate units is also a subclass of SaleUnit. The statistical data of various outlets is different: Some data is stored in the database table and can be obtained through some statistical operations; some are directly stored in a field of the data table and can be directly found out; there is also an Excel worksheet sent every day. For each different sales outlet, you can use the same interface to access them and obtain the required data.

The combination mode can accurately reflect the aggregation relationship between sales outlets, and provides a very consistent interface for query and statistics. Callers do not have to distinguish specific outlet types. In a similar situation, when we find that some objects in the requirement have an aggregation relationship and want to do something common to them, we can adopt the combination mode.

Now there is a serious problem: Yes, there is no need to differentiate the specific outlet type for calling an object, but where are they created, during creation, we still need to differentiate the types of outlets. complicated code is just transferred from one place to another. What are the advantages of this operation? To explain this question, we will introduce another common mode: Factory ).

The factory mode is used to completely disconnect the relationship between the caller and the called specific type. It creates a specific type in a factory and the caller obtains the object instance from the factory. The caller does not need to know how the object is created or what type it is created. The following example illustrates the usefulness of the factory model.

This is an electrical equipment monitoring system. One of his tasks is to collect the running data of various devices from sensors installed in various places and display them on the monitor in a centralized manner. You can also define alarm conditions on the device. When the collected data meets the alarm conditions, an alarm is sent to the monitoring personnel, and an alarm sign is displayed on the monitor. The basic situation is as follows:

A device can have multiple signals, such as a transformer, which can have various signals, such as voltage, current, and coolant temperature, which are collected by different sensors. Each signal collects a piece of data at intervals, and some data is directly collected, the other is calculated based on multiple signals (for example, if there are n nodes on an electric network ring road, we already know the voltage of n-1 nodes, the voltage of the last node can be calculated. Other data is a speculative value (which needs to be estimated based on some empirical data ). After the sensor collects the signal data, the program must judge the value of the data. Sometimes it must combine other signals to determine whether the alarm conditions are met and send an alarm.

Data collection is a very complex task. Many devices need to be monitored. The data meaning is complex, and the communication methods of sensors are also different. Fortunately, you have built a comprehensive collection system to collect real-time data of devices. The Collection System communicates with various sensors to continuously input the collected real-time data into a data table. Below are some data in this table:

With such a system, the problem of direct data collection is solved. However, different signal types still have different interpretations of this data, and we still have to deal with this problem. There are three types of signals:

1. analog signal: check real-time data from the Integrated collection system, and add a unit (such as volt and ampere) to display the data;

2. Status Signal: You need to define a status description. For example, a switch is closed when the collected data is greater than 0, and is disconnected when the value is equal to 0;

3. Speculative signal: The data of some signals cannot be obtained from the comprehensive collection system and must be calculated using formulas. Add a unit to the calculated value.

We can store the definition of signals in the database. The data is as follows:

The TYPE field indicates the TYPE of the signal. A is A analog signal, S is A state signal, and P is A speculative signal. The corresponding signal instance is created based on this field, and data processing for different types of signals is handled by the corresponding subclass. The analog signal will display the collected data plus units. The status signal will display the collected data according to the STATE_DESCRIPTION definition; the speculative signal calculates the signal value according to the PRESUME_FORMULE definition, and then displays the UNIT.

We can create the Signal subclass in the device. However, if we use a factory, it is responsible for the establishment of the Signal object, which completely isolates the relationship between the device and each sub-class of the Signal. When a device calls a signal object, it does not need to know the type of the instance. The Factory Code is as follows:

 

Class SignalFactory
{
Public static Signal CreateSignal (string dev, string sig)
{
// Obtain the definition of the signal
String SQL =
"SELECT * from sig where dev = '" + dev + "' and sig = '" + sig + "'";
// Query database tables

// Determine the type to be created
Signal signal = null;
If (type = 'A ')
{
Signal = new AnalogSignal ();
}
Else if (type ='s ')
{
Signal = new StateSignal ();
}
Else if (type = 'P ')
{
Signal = new PresumeSignal ();
}
Else
{
Return null;
}

// Set Signal configuration parameters
Signal. SetUnit (unit );
Signal. SetStateDescription (state_description );
Signal. SetPresumeFormule (presume_formule)

Return signal;
}
}

If we need to display a signal on the device, we can:

 

Signal sig = SignalFactory. CreateSignal (dev, sig );
String s = sig. GetDisplayString ();

In fact, we can also adopt some small means, such as reflection, to thoroughly isolate the sub-classes of Signal from other code, even SignalFactory does not need to be associated with the subclass. We can modify the signal configuration data:

The TYPE field was originally designed as A identifier (A, S, and P), and now the TYPE of namespace and name are directly recorded. When creating an instance, SignalFactory directly finds the content of the TYPE field, and then creates the desired instance Using Reflection based on the class name. In this way, no matter the creator or caller of Signal needs to know which type they create and call, the data and display processing of various signals is completely the responsibility of each sub-class of Signal, and the program is well compliant with the open and closed principle. If there are some very unique signal collection and calculation methods in the future, and even have to use hard coding to implement them, it will not affect other codes, and it is very easy to maintain.

We used a factory to solve the problem of signal data collection, and left a possibility of expansion for possible next changes. Next let's take a look at how to handle the alarm. First, let's take a brief look at the formation of alarms: first, collect the latest real-time data on the device, and then determine whether the data meets the alarm conditions according to a rule. Generates an alarm on the device when the conditions are met. In most cases, an alarm is related to only one device. However, an alarm condition must judge multiple signals on multiple devices at the same time. So we designed the following structure:

The alarm definition is saved in the alarm definition data table as follows:

The CONDITIONA field in the table indicates the alarm condition. This is a formula. When determining the condition, substitute the value of the signal and determine whether the condition is met. If conditions are met, an alarm is generated.

The running sequence of the program is as follows: the device object obtains the real-time data on the signal it contains, finds each alert object associated with it, and calls its Judge method in turn. The Judge method determines whether an alarm exists based on the alarm condition formula. If an alarm exists, set the HasAlarm attribute of the relevant device to True. In this way, the main functions of the program are implemented.

The following is a client interface of the program:

On the left side of the interface is a tree, indicating the classification relationship of devices. Each leaf represents a device. When you click a device on the tree, the List View on the right shows the signals and collected data on the device. If there is an alarm on the device, the corresponding Tree node should be marked with a significant color, the status bar displays the latest alarms.

To refresh the interface, you can set a timer on the form. Check the HasAlarm attributes of all devices at intervals and find the devices with alarms, change the icon of the device in the tree, and then display the alarm content on the status bar. However, there is a disadvantage in this process. No matter how you set the timer time interval, it is not appropriate. If the timer time is too long, some alarms may take a long time to be displayed. If the time is too short, there may be no alarms for many refresh attempts, which consume resources in vain. This refreshing mechanism is unreasonable. To solve this problem, you can use the observation mode (Observer ). An object needs to wait for another object to send a message, and then take response measures. The object waiting for the message does not need to know how and when the message occurs, the object that sends the message does not need to know who will pay attention to the message and how to respond. In this case, the observation mode can be used.

There is a very simple way to use C # To implement the observation mode, that is, events. We can define an event on the device: an alarm. When the HasAlarm attribute of the device is set, the device checks the parameters. If the parameter is True, an alarm is triggered. The code snippet of the device is as follows:

 

Class Device
{
Public event System. EventHandler Alarm; // defines an Alarm event

Public Device ()
{
This. Alarm + = new System. EventHandler (this. Device_Alarm );
}

Public void SetHasAlarm (bool has)
{
If (has = true)
{
Alarm (this, null); // sends an Alarm event
}
}

Private void Device_Alarm (object sender, EventArgs e)
{
}
}

When an Alarm is triggered on the device, the device object sends an Alarm event. The Tree View on the interface can capture this event and set the corresponding Tree node icon to red. The status bar can also capture this event to display alerts on the device. This is a more reasonable and efficient method than regular round robin.

Is the object design reasonable? The reference criterion is whether the design reflects the actual concept of business requirements. To truly reflect business needs, the most fundamental method is to deeply understand the needs and thoroughly explore the work and thoughts of business personnel, they even noticed that they could not express themselves in words. This is common in a large number of enterprise support systems. Experienced business personnel will certainly accumulate many such ideas. The object model that embodies these ideas is the best. This problem cannot be avoided if a software system is required to help business personnel. The rational use of the design model can minimize the complexity of the system, but in the final analysis, the complexity is determined by the business needs. After the object design is basically clear, the design pattern can help designers better process the complex relationships between objects and build a simpler and more stable object model. At the same time, designers can also get inspiration from the design model to discover some details that were not noticed.

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.