none
Interface and Abstract Classes Code RRS feed

  • General discussion

  • Hi Friends!

    I was wondering what is best practice for where in your project should you place or structure the code for your Interfaces and Abstract Classes. In particular if you are using the GoF Abstact and Factory Method Patterns. I guess I am asking should I make a class Library or have a special folder. Thanks !

    • Changed type CoolDadTxModerator Friday, January 18, 2019 9:15 PM This is a discussion more than a technical question
    Friday, January 18, 2019 8:40 PM

All replies

  • Completely depends upon your needs but most people separate business logic (which includes interfaces and abstract classes) from UI and possibly data layer. In this case projects are most appropriate.

    Where the contracts reside is a personal preference. Some people create a separate project just for contracts while others put it in the layer it is appropriate for. There is no right or wrong answers here. Part of it will boil down to how many you have, how much separation you want and how big the project is.

    For a simple app I would keep everything together (KISS principle). For web apps I tend to put contracts with the business layer (for business interfaces) or data layer (for data interfaces). For API projects though clients need the contracts so a separate contract project with the corresponding data types is better.


    Michael Taylor http://www.michaeltaylorp3.net

    Friday, January 18, 2019 9:19 PM
    Moderator
  • With an interface,  I apply the "New is glue" principle and loose coupling where I am using Dependency Injection by means of an IoC.

    https://ardalis.com/new-is-glue

    <copied>

    Decoupling Services from Providers
    New is Glue. It binds your code to a particular collaborator.
    If there is any chance you’ll need to be flexible about which implementation your code will need, it’s worth introducing an interface to keep your code loosely coupled.
    It doesn’t matter what the service is you need – you can always replace it with an interface even if your class is the only one that uses it.

    <end>

    https://msdn.microsoft.com/en-us/magazine/mt703433.aspx?f=255&MSPPError=-2147217396

    <copied>

    When looking at code to evaluate its coupling, remember the phrase “new is glue.”
    That is, anywhere you see the “new” keyword instantiating a class, realize you’re gluing your implementation to that specific implementation code.
    The Dependency Inversion Principle (bit.ly/DI-Principle) states: “Abstractions should not depend on details; details should depend on abstractions.” In this example, the details of how the controller pulls together the data to pass to the  view depend on the details of how to get that data—namely, EF.

    <end>

    An abstract class, I use it as base class that all classes inherit from the base class.

    So in the example code, you see the controller in the MVC presentation layer use inherit from the basecontroller. Any exception that is thrown in the controller, any code the controller calls throws an exception, the basecontroller will catch the exception.

    You don't see the New keyword being used between the controller and the code it is calling in an object, becuase the code being called is in an object that uses an Interface that the IoC, Unity knows about and the object has been instanced inside the IoC container, which was dependency injected into the controller.

    As far as using that factory pattern to generate cookie cutter objects, you'll know it when you see it when the pattern can be used. It's kind of rare maybe never at all that you'll use the factory pattern.

    You see Interface being used heavily in layered, n-tier and  other architectural patterns that also promote loose coupling.

    https://docs.microsoft.com/en-us/previous-versions/msp-n-p/ee658117(v=pandp.10)

    using System;
    using System.Web;
    using System.Web.Mvc;
    using System.Web.Routing;
    using log4net;
    
    namespace MVC.Controllers
    {
        public abstract partial class BaseController : Controller
        {
            private ILog _logger;
    
            protected BaseController()
            {
                _logger =  LogManager.GetLogger(typeof(BaseController));
            }
    
            protected override void OnException(ExceptionContext filterContext)
            {
                AppException appException = new AppException(Convert.ToString(filterContext.Exception))
                {
                    Type = filterContext.GetType().ToString(),
                    StackTrace = filterContext.Exception.StackTrace,
                    Source = filterContext.Exception.Source,
                    InnerException = Convert.ToString(filterContext.Exception.InnerException)
                };
    
                _logger.Error(appException.ToString());
    
                Server.ClearError();
    
                RedirectToControllers("Home", "Error");
            }
    
            private void RedirectToControllers(string control, string action)
            {
                var routeData = new RouteData();
    
                routeData.Values["controller"] = control;
    
                routeData.Values["action"] = action;
    
                IController controller = new HomeController();
    
                ((IController) controller).Execute(new RequestContext(
                    new HttpContextWrapper(System.Web.HttpContext.Current), routeData));
            }
        }
    }
    using System.Web.Mvc;
    using MVC.Models;
    
    namespace MVC.Controllers
    {
        [Authorize]
        public class StudentsController : BaseController  
        {
            private IStudentModels studmods;
            public StudentsController(IStudentModels studentModels)
            {
                studmods = studentModels;
            }
    
            // GET: Students
    
            [AllowAnonymous]
            public ActionResult Index()
            {
                return View(studmods.GetStudents());
            }
    
            //[AllowAnonymous]
            public ActionResult Details(int id = 0)
            {
                return id == 0 ? null : View(studmods.GetStudentById(id));
            }
            public ActionResult Create()
            {
                return View(studmods.Create());
            }
    
            [HttpPost]
            public ActionResult Create(StudentViewModels.Student student)
            {
                if (ModelState.IsValid)
                {
                    studmods.Create(student);
                    return RedirectToAction("Index");
                }
    
                return View(student);
            }
    
            public ActionResult Edit(int id = 0)
            {
                return id == 0 ? null : View(studmods.Edit(id));
            }
    
            [HttpPost]
            public ActionResult Edit(StudentViewModels.Student student)
            {
                if (ModelState.IsValid)
                {
                    studmods.Edit(student);
                    return RedirectToAction("Index");
                }
    
                return View(student);
            }
    
            public ActionResult Delete(int id = 0 )
            {
                if (id > 0) studmods.Delete(id);
                
                return RedirectToAction("Index");
             }
        }
    }

    namespace MVC.Models
    {
        public interface IStudentModels
        {
            StudentViewModels GetStudents();
            StudentViewModels.Student GetStudentById(int id);
            StudentViewModels.Student Create();
            void Create(StudentViewModels.Student student);
            StudentViewModels.Student Edit(int id);
            void Edit(StudentViewModels.Student student);
            void Delete(int id);
        }
    }
    
    ==============================================
    
    using System.Collections.Generic;
    using Entities;
    using WebAPI.Controllers;
    
    namespace MVC.Models
    {
        public class StudentModels : IStudentModels
        {
            private IStudentControllerAPI studapi;
            public StudentModels(IStudentControllerAPI studentControllerApi)
            {
                studapi = studentControllerApi;
            }
    
            public StudentViewModels GetStudents()
            {
                var dtos = studapi.GetStudents();
               
                var vm = new StudentViewModels {Students = new List<StudentViewModels.Student>()};
    
                foreach (var dto in dtos)
                {
                    var student = new StudentViewModels.Student
                    {
                        StudentID = dto.StudentID,
                        LastName = dto.LastName,
                        FirstName = dto.FirstName,
                        EnrollmentDate = dto.EnrollmentDate
                    };
    
                    vm.Students.Add(student);
                }
    
                return vm;
            }
    
            public StudentViewModels.Student GetStudentById(int id)
            {
                var dto = studapi.GetStudentById(id);
    
                var student = new StudentViewModels.Student
                {
                    StudentID = dto.StudentID,
                    FirstName = dto.FirstName,
                    LastName = dto.LastName,
                    EnrollmentDate = dto.EnrollmentDate,
                    EnrollsandCourses = new List<EnrollandCourseViewModel.EnrollandCourse>()
                };
    
                foreach (var dtoec in dto.EnrollsandCourses)
                {
                    var ec = new EnrollandCourseViewModel.EnrollandCourse
                    {
                        Credits = dtoec.Credits,
                        Grade = dtoec.Grade,
                        Title = dtoec.Title
                    };
    
                    student.EnrollsandCourses.Add(ec);
                }
    
                return student;
            }
    
            public StudentViewModels.Student Create()
            {
                var student = new StudentViewModels.Student();
    
                return student;
            }
    
            public void Create(StudentViewModels.Student student)
            {
                var dto = new DTOStudent
                {
                    StudentID = student.StudentID,
                    FirstName = student.FirstName,
                    LastName = student.LastName,
                    EnrollmentDate = student.EnrollmentDate
                };
    
                studapi.CreateStudent(dto);
            }
    
            public StudentViewModels.Student Edit(int id)
            {
                var dto = studapi.GetStudentById(id);
    
                var student = new StudentViewModels.Student
                {
                    StudentID = dto.StudentID,
                    FirstName = dto.FirstName,
                    LastName = dto.LastName,
                    EnrollmentDate = dto.EnrollmentDate
                };
    
                return student;
            }
    
            public void Edit(StudentViewModels.Student student)
            {
                var dto = new DTOStudent
                {
                    StudentID = student.StudentID,
                    FirstName = student.FirstName,
                    LastName = student.LastName,
                    EnrollmentDate = student.EnrollmentDate
                };
    
                studapi.UpdateStudent(dto);
            }
    
            public void Delete(int id)
            {
                studapi.DeleteStudent(id);
            }
        }
    }

    Friday, January 18, 2019 11:29 PM
  • Hello,

    I use interfaces in two ways - contract and facada. What do I mean?

    Contract

    When I build some system there are some layers. Most interesting part of each system is business layer because it is layer which customer needs and it is what customer wants to create this system because there are their business rules, workflows, etc… I try to write this layer by some DDD patterns and principles. It means I try to write it without some dependencies to another layers. So I need to define some interfaces which another layer will implemented. It is contract. It is known as dependency inversion, which is subset of dependency injection and inversion of control. 

    So my business layer doesn't reference any other layer in project. This layer is referenced by application layer (or service layer) and data layer. You can find term infrastructure layer because when you have dependency to third party web services in base meaning it is data layer as well as. 

    Facada

    I use facada pattern on application layer which is system frame. It defines all functions which system can provide. Based on use cases I can define interface for each actor. In base meaning it is contract too but it is interaction contract with actors which can be another system. In the end I have several interfaces and each system can use interface which defines contracts which them. It is facada pattern because it shows only part of system and not whole system. 

    Abstract classes

    I use abstract classes to provide some pattern. Typically template, strategy or abstract factory pattern. So I use it for modeling system behavior and these classes are not accessed from outside of layer.

    Saturday, January 19, 2019 8:20 AM