1. Name 3-4 design principles/practices that an interface helps support.
Single responsibility principle - A class should only have one responsibility. If there are multiple classes with different responsibilities, but each class utilizes the same method, then an interface can support this. For example an alarm clock, watch, cell phone, wall clock, and clock on a computer all have different responsibilities, but no matter which one of those you 'grab' it still has to tell time, so "Time" could be an interface that applies to all the subclasses.
Dependency inversion principle - High-level modules should not depend on low-level modules, but should depend on abstractions. Abstractions should not depend on details, details should depend upon abstractions. High-level and low-level components need to be separated in different libraries, with the behavior of the high-level component defined by interfaces. The low-level component then depends on the high-level interface to know what to do. A good example would be a car - instead of coming up with all the details on how pressing the accelerator makes the car go one could say "the car needs to stop, the car needs to go, the car needs to turn" then each subclass (accelerator, brakes, steering wheel, wheels, engine) can be detailed based on the higher level interface decisions.
Interface segregation principle - Interfaces should only contain methods it will actually use, and customers/users should never be forced to depend on a method that is not used. Without interfaces this principle would not exist. If an interface is responsible for more than one thing (see single responsibility principle) it should be broken down into more specific, individual interfaces. This will result in fewer issues or complications as a system is modified, updated, refactored, or becomes more complicated over time.
2. Why is it better to "program to the interface" and not "the concrete" class?
An interface is really defined by an abstract class, without including any implementations of the underlying functions. As an abstract class the interface is really a base class from which other classes can be derived. This new derived class (sub-class) will contain the actual implementation of the functions in the base class. This newly derived sub-class is a concrete class.
If you are programming to the concrete class and something changes, then each of those concrete classes will need to be updated as well. This could result in a lot of work and numerous changes if there are a large number of concrete classes. Furthermore if the implementation of a method is only slightly different across concrete classes you can create a base class containing the common method, which will be invoked from the more specific/individualized information contained within the subclasses - so "animals" would be an abstract class (interface) and individual animals can be subclases with 'concrete' traits. Since all animals eat, "eat" can be another interface with the derived sub-classes providing the 'concrete' details of what the animals eats, how it eats, etc.
Or another example (and I really hope I'm understanding this correctly): Instead of writing code to "add to database" for every class and their details, you can create an "add to database" interface, then as long as the class can call the method to add to database, it can use any criteria specific to the class to figure out exactly HOW to add to the database.
3. What are some other uses for using an interface that may not have been mentioned in the course content?
Gives the end user/developer additional flexibility - if, for example, the final product needs to generate some sort of report on a regular basis, but the report might change, or when, or other factors, then creating an interface that can generate reports, and maybe a separate interface to schedule reports, will be useful when the reports themselves change.
An interface can be used as 'notes' to ensure that appropriate functionality is included in more specific classes. If an interface will get/set a particular string name, then it's easier to remember to make sure that string is set in any classes that will implement the interface.
The use of interfaces creates what is essentially a plug-and-play architecture making it easier to replace or swap individual components. Any interchangeable components will utilize and implement the same interface so it does not require any extra programming to use them.