Today I'm going to talk about access modifiers. If you don't know what they are or how to use them, check out the first section of this MSDN topic.
Read it? Understood it enough to get a program to compile? Great, then lets get to it. I'll start with the when, then explain the why.
When?
Use private first for anything that other classes don't need to see. You can always make something protected or public later but, when you do, ask yourself if there's a way you can keep it private and expose the work you want to do with the private fields as a public method instead of exposing the fields directly.
Public should be used only when absolutely necessary. For example, if you find yourself writing something like this:
public class PersonDetails { public int Age { get; set; } public DateTime Birthday { get; set; } public bool IsFemale { get; set; } public string FirstName { get; set; } public string LastName { get; set; } public DateTime WeddingDate { get; set; } } static void Application_Main() { var person = new PersonDetails(); person.FirstName = "Jane"; person.LastName = "Bloggs"; person.IsFemale = true; person.Birthday = new DateTime(1984, 10, 24); person.Age = (DateTime.Now - new DateTime(1984, 10, 24)).Years; if (justMarried) { if (person.IsFemale) { person.LastName = "Sanders"; } person.WeddingDate = DateTime.Now; } Console.WriteLine( person.FirstName + " " + person.LastName + " is " + person.Age); }
Then you should get in the habit of thinking "that's a lot of person-dot-somethings, this would be better off as private fields and a public method" and rearrange it to be a bit more like this:
public class PersonDetails { public int Age { get { return (DateTime.Now - _birthday).Years; } } public string FullName { get { return _firstName + " " + _lastName; } } private DateTime _birthday; private string _firstName; private string _lastName; private bool _isFemale; private DateTime _weddingDate; public PersonDetails( string firstName, string lastName, DateTime birthday, bool isFemale) { _firstName = firstName; _lastName = lastName; _birthday = birthday; _isFemale = isFemale; } public void JustMarried(string newLastName) { if (_isFemale) { _lastName = newLastName; } _weddingDate = DateTime.Now; } } static void Application_Main() { var person = new PersonDetails( "Jane", "Bloggs", new DateTime(1984, 10, 24), true); if (justMarried) { person.JustMarried("Sanders"); } Console.WriteLine(person.FullName + " is " person.Age); }
You probably won't stop there, because once everything is sorted, it'll be easier to see other improvements you can make. This process of improvement is called refactoring and it is an important and iterative process - meaning you do it over and over. Your classes will end up looking a lot more descriptive, useful and less error prone if you get into this habit.
Use protected when you're inheriting from your class and need access in the child class to methods and properties that exist in the parent class but aren't public.
You probably won't need internal for now as it's mostly used in third party libraries to create classes that are public to their code, but hidden from yours.
Why?
Good Object Oriented Programming is all about encapsulation. Encapsulation just means that your objects (that's the classes and structs you write) are self-contained. A good object hides how it does something and only publicly exposes enough methods and properties to cover what it does.
Exposing the bare minimum functionality publicly to other classes promotes readability, it also promotes re-usability (the code is in a neat little package that doesn't rely on dozens of other classes) and it promotes scalability. It's also less likely to have errors in it because being all packaged nicely means it's easier for you to keep track of and - if you do make a mistake - it'll be easier to figure out what's going wrong, because there are fewer elements to your code that could be affecting a private field or property compared to a public one.
Let's take a side by side look at the public members of our example before and after we refactored it.
Before | After |
Age (get / set) | Age (get only) |
Birthday (get / set) | FullName (get only) |
IsFemale (get / set) | JustMarried() |
FirstName (get / set) | |
LastName (get / set) | |
WeddingDate (get / set) |
As you can see, the list on the right is a lot shorter and tells us how we're expected to use the class without having to dig around inside of it or find out how everything else is using it. In big projects, well designed classes that let you understand the what without the how become the difference between it taking 10 minutes to change something and 10 hours. You'll come to find that well structured code also helps you feel more confident that your change isn't secretly breaking something somewhere else!
Further Reading
If this topic has you chomping at the bit for more, then you should check out the readonly keyword. In the same way that private protects from public misuse, readonly protects from after-construction misuse.
You should also definitely check out Interfaces. Interfaces don't have any implementation (implementation is what we call the how in programming). Their purpose is to define the contract (the what) that a class must fulfill publicly in order to be considered an implementation of that interface. If you'd like to see a W&W article on interfaces, let me know in the comments!
No comments:
Post a Comment