Not everyone needs to see all types. Therefore, we do not need to set every type we create to public. We should provide the lowest visibility for each type, you only need to achieve the goal.
When a new type is created in Visual Studio, the default visibility provided is internal, which is visible in the Assembly. If we declare the type as public, any code that uses this Assembly can access this type. In this way, unnecessary repetitive work may be added during future maintenance, the lower the visibility of the type, the lower the workload for modification in future updates, and the fewer places to access a piece of code, the fewer changes need to be made after the code is changed.
We should expose only the functions to be exposed. For other types, we can use different methods to reduce their visibility, such as setting the type to internal or private, note that the type of visibility into private can also implement interfaces. We can also set these classes to internal classes.
Let's take a look at the following code change process: the first version.
1 public class PhoneValidator
2 {
3 public bool ValidateNumber( PhoneNumber ph )
4 {
5 // perform validation.
6 // Check for valid area code, exchange.
7 return true;
8 }
9 }
The above Code provides the phone number verification function. You can instantiate the phonevalidator object directly during use, and then call the validatenumber method of the object for verification. The phonevalidator type here is public.
As time goes on, our verification methods may become richer, and a second version of code will be generated.
Code
1 public interface IPhoneValidator
2 {
3 bool ValidateNumber( PhoneNumber ph );
4 }
5
6
7 internal class USPhoneValidator : IPhoneValidator
8 {
9 public bool ValidateNumber( PhoneNumber ph )
10 {
11 // perform validation.
12 // Check for valid area code, exchange.
13 return true;
14 }
15 }
16
17
18 internal class InternationalPhoneValidator : IPhoneValidator
19 {
20 public bool ValidateNumber( PhoneNumber ph )
21 {
22 // perform validation.
23 // Check international code.
24 // Check specific phone number rules.
25 return true;
26 }
27 }
28
The above Code defines an interface named iphonevalidator. The interface type is public, and then two types that implement this interface are defined, namely usphonevalidator and internationalphonevalidator, both types are internal. In this case, you need to declare an iphonevalidator instance and then call the validatenumber method of the instance. Note: you cannot directly instance objects here. This process needs to be placed in the assembly of the iphonevalidator type and can be instantiated using the factory mode.
In the above example, the software design principles are embodied: 1) interface-oriented programming can make the program more flexible; 2) command mode or template mode. If the interface is directly implemented, the command mode is used. If the abstract base class is integrated and the common logic is placed in the base class, the template mode is used.
The classes and interfaces we expose to the outside world through the public method should be our contract: we must use them in a consistent manner. The more chaotic the program interfaces, the more limited we will be in the future, the fewer public types we expose, the more options we will have for future extension and change implementations.