Page 2 of 3 FirstFirst 123 LastLast
Results 11 to 20 of 26
  1. #11
    Join Date
    Mar 2004
    Posts
    0
    I don't necessarily think that's something you should be doing. Having an object add itself to a global collection on construction is... backwards, to say the least. Instead, there should be a factory that instantiates the SpcialBase objects, then adds it to a collection. Throw in generics, and you get type-safety and static typing (over reflection, for example).

    What you have there is like... inverted dependency injection

    Magic code like this seems cool and elegant - but it truly does impact understandability and maintainability. You also wouldn't be able to re-use any of your SpecialBase child classes in any context that doesn't require them to publish themselves to that particular global collection... I just wanted to point out that you might want to avoid writing code like that.

  2. #12
    Join Date
    Dec 2002
    Posts
    39
    Back to interfaces: I usually explain them as shared functionality, extracted for accessibility.

    A ball can bounce. A tire can bounce. However, those two items will probably not share a common ancestry (other than Object). Instead you can implement an interface that represents their common functionality - IBounceable. Then when you want to bounce an object you check if it supports the IBounceable interface, cast to IBounceable, and then use the methods of the interface as needed to "bounce" your object.

    Interfaces are the elegant solution to multiple class derivation (which is not allowed in C#; you can only derive from a single parent).

  3. #13
    Join Date
    Mar 2004
    Posts
    0
    Yeah, thank god C# doesn't support multiple inheritance.

    Another use case of inheritance is swapping out implementations of code during runtime. For example, you may have a class called UserRepo that is responsible for adding and listing users. However, you may want to change the way that your application gathers that list (xml/rdbms/ldap). So what you would do is create an interface that represents the "contract" of the system (_what_ this system does) and multiple implementations of that contract (_how_ the system does it). You you would have:

    Code:
    class User
    {
        public string FirstName { get; set; }
    }
    
    interface IUserRepo 
    {
        IQueryable<User> Users { get; }
        void AddUser(User u);
    }
    And multiple implementations of that interface:

    Code:
    class NHibernateUserRepo : IUserRepo 
    {
        // The details aren't important - but know here that the application is now gathering user objects from a relational database (mysql, for example)
        public IQueryable<User> Users { get { return Application.CurrentContext.CreateQuery("from User").List<User>().AsQueryable(); }
    
        public void AddUser(User u)
        {
            ITransaction trans = Application.CurrentContext.BeginTransaction();
            Application.CurrentContext.SaveOrUpdate(u);
            trans.Commit();
        }
    }
    or

    Code:
    class FlatFileUserRepo : IUserRepo 
    {
        // Ugly code alert... Was just fun to pump that out, but I'd never use that in production :p
        public IQueryable<User> Users { get { return(new StreamReader("users.txt")).ReadToEnd().Split('\n').Select<string, User>(line => new User() { FirstName = line }); } }
        
        public void AddUser(User u)
        {
            StreamWriter sw = new StreamWriter("users.txt", true);
            sw.WriteLine(u.FirstName);
            sw.Close();
        }
    }
    Now let's say you have an action that prints out user's name and/or creates users... Something like:

    Code:
    class UserController
    {
        private IUserRepo m_Users;
    
        public UserController(IUserRepo users)
        {
            m_Users = users;
        }
    
        public void List()
        {
            Console.WriteLine("Listing Users");
            m_Users.Users.ToList().ForEach(u => Console.WriteLine(u.FirstName));
        }
    
        public void Create()
        {
            Console.WriteLine("Creating a new User");
            Console.Write("Enter First Name: ");
            m_Users.Add(new User() { FirstName = Console.ReadLine(); });
        }
    }
    You can now consume it with this:

    Code:
    class Program
    {
        public static void Main()
        {
            Console.Write("Use database (y) or flat file (n) for gathering users: ");
            bool useDatabase = Console.ReadKey() == 'y';
    
            IUserRepo users = useDatabase ? new NHibernateUserRepo() : new FlatFileUserRepo();
    
            UserController userController = new UserController(users);
    
            userController.Create();
            userController.List();
        }
    }
    Now UserController doesn't care how users are stored or retrieved - but because it knows about the IUserRepo interface, it has enough information about the contract to do it's thing. This is the power of interfaces.
    Last edited by Nelson LaQuet; 05-10-2010 at 11:41 PM.

  4. #14
    Join Date
    Feb 2005
    Location
    Bellevue, WA
    Posts
    3,251
    Quote Originally Posted by Trystan View Post
    Interfaces are the elegant solution to multiple class derivation (which is not allowed in C#; you can only derive from a single parent).
    Quote Originally Posted by <> View Post
    Yeah, thank god C# doesn't support multiple inheritance.
    Interfaces provide a way to work around the ability to do multiple inheritance, but it's not necessarily an elegant solution. The inability to do multiple inheritance can lead to increased code that needs to be duplicated or supported.

    Example you give is about IBounceable. Well, what if you also have IDestructable.

    Code:
    public interface IBounceable {
      double BounceCoefficient { get; set; }
      //...
    }
    
    public interface IDestructable {
      double TimeToDestruct { get; set; }
      //...
    }
    Each time you implement that interface you must implement the property and getter/setter. Now if you always want to constrain the values to ranges between 0.0 to 1.0 for example, you need to come up with some way to provide that implementation consistently (static method in an abstract class maybe).

    There are many examples where multiple inheritance is actually a cleaner way to write your code and requires less code and a cleaner design to get the functionality required.

    "Programming today is a race between software engineers striving to build bigger and better idiot-proof programs, and the Universe trying to produce bigger and better idiots. So far, the Universe is winning." ~Rich Cook

  5. #15
    Join Date
    Mar 2004
    Posts
    0
    For validation: that is either part of the implementation (some inheriting classes may have different requirements) or part of the contract (should be located inside of the contract itself). The Data Annotation framework, for example, is a great way to use attributes to describe validation logic - though of course, it doesn't enforce that logic in and of itself.

    I'm not a big fan of inheritance, to be honest. Inheritance is the ultimate coupling, and is less flexible then composition. Of course they solve different problems, but I've seen inheritance used in many places that composition would be more applicable. I'm not arguing that multi-inheritance, or inheritance itself, is a bad thing or is never useful - because they can very much be. But they can also be abused incredibly easily. I guess it's to the discretion of the coder, as always.

  6. #16
    Join Date
    Feb 2005
    Location
    Bellevue, WA
    Posts
    3,251
    The DAF is a horribly broken validation mechanism tying your business logic with your UI validation; DAF is only triggered in certain situations. If you want to call the validation in your metadata (or rather, guarantee the validation is called, as you mentioned), you need to explicitly do so - how is this a good thing? To selectively apply data validation is questionable at best.

    This is ugly!
    Code:
    [Display(Name="Name", Description="First Name + Last Name.")]
    [Required(ErrorMessage = "First Name is required.")]
    [RegularExpression(@"^[a-zA-Z''-'\s]{1,40}$", ErrorMessage = "Numbers and special characters are not allowed in the name.")]
    public string FirstName
    {
        get { return m_FirstName; }
         set
        {
            Validator.ValidateProperty(value, new ValidationContext(this, null, null) { MemberName = "FirstName" });
            m_FirstName = value;
        }
    }
    Also, metadata doesn't necessarily inherit up the chain so you need to check each individual metadata attribute to determine if inheritance works or not.

    The main problem with composition is you have to either expose the internal items that your a hiding to get to the methods for what you need or redefine all of the methods. That's bad.

    Composition is great for things like making a stack using the implementation of a linked list. But inheritance is much better for creating a double-linked list. Each is good for something, both can be used poorly though, as you mentioned.

    "Programming today is a race between software engineers striving to build bigger and better idiot-proof programs, and the Universe trying to produce bigger and better idiots. So far, the Universe is winning." ~Rich Cook

  7. #17
    Join Date
    Mar 2004
    Posts
    0
    I don't necessarily agree. Validation is the concern of data integrity - which very much is a part of your domain model. I don't care what view is being invoked, I wouldn't want invalid data making it's way into my database. Data annotations are simple, yes, but they do cover many of the most common forms of validation in a (in my opinion) clean way.

  8. #18
    Join Date
    Feb 2005
    Location
    Bellevue, WA
    Posts
    3,251
    Forms validation is one specific area of need for validation though... DAF would be a horrible solution to the problem I presented around validation. DAF allows for more RAD development, sure, that's fine and dandy, but you need to understand that it has a cost too - namely the debugging story isn't all that spectacular if you need to dig into which part of the validation is failing (unless you wrote the validator).

    My point with DAF is that unless you explicitly invoke the validators in your setters, the view is crucial to whether or not validation is invoked.

    "Programming today is a race between software engineers striving to build bigger and better idiot-proof programs, and the Universe trying to produce bigger and better idiots. So far, the Universe is winning." ~Rich Cook

  9. #19
    Join Date
    Dec 2002
    Posts
    39
    Quote Originally Posted by owensd View Post
    Interfaces provide a way to work around the ability to do multiple inheritance, but it's not necessarily an elegant solution. The inability to do multiple inheritance can lead to increased code that needs to be duplicated or supported.
    Encapsulation of the logic into a separate class/entity and then encapsulation of that newly created entity into the classes which use it. A bit more loosely coupled and an explicit definition/association.

    I'm sure there's plenty of real world usage scenarios for multiple inheritance - I've just never seen one. That's just my experience, and my opinion.

  10. #20
    Join Date
    Feb 2005
    Location
    Bellevue, WA
    Posts
    3,251
    Quote Originally Posted by Trystan View Post
    Encapsulation of the logic into a separate class/entity and then encapsulation of that newly created entity into the classes which use it. A bit more loosely coupled and an explicit definition/association.
    Let's take a look at a simple example: herbivores, carnivores, and omnivores. An omnivore is simply both a carnivore and an herbivore. How would you propose getting around this problem and providing default behaviors for both herbivores and carnivores, such as 'hunt' and 'graze'?

    "Programming today is a race between software engineers striving to build bigger and better idiot-proof programs, and the Universe trying to produce bigger and better idiots. So far, the Universe is winning." ~Rich Cook

Page 2 of 3 FirstFirst 123 LastLast

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •