As always, comments welcome!

 

Object Oriented Design

         This is not an OO Design class

         A type represents a set of responsibilities

         Modeling the real world

         Group related responsibilities together in a class

         Only 5% of developers will ever explicitly extend base classes

         But 100% will use classes

 

Danger of over design

         The most common library design mistake

         A new dev/pm is designing the widget feature

          Wants it to be extensible and feature rich

         The reality of shipping hits

          Design only partly thought out

          Long bug tail

          Forced hard cuts

          We ship it cumbersome and broken

         In V.next

          We now we know the extensibility needed

          But blocked by the broken design the shipped

 

Abstract and Base classes

         Base classes serve as the root of an inheritance hierarchy

         Abstract classes are a special kind of base class that are non-instantiable and may contain members that aren’t implemented

         Prefer broad, shallow hierarchies

         Less than or equal to 2 levels – Rough rule!

         Contracts and responsibilities are difficult to maintain and explain in deep complex hierarchies

         Consider making base classes not constructible

         Make it clear what the class is for

         Provide a protected constructor for subclasses to call

         System.Exception should not have had a public constructor

 

Virtual, Abstract and Non-virtual

 

         Virtual members are points of specialization or callbacks in your code

public virtual int Length { get {..} }

         Abstract  members are required points of specialization in your code

public abstract int Read()

         Non-virtual members cannot be overridden in derived types

public string Remove (int index, int count)

 

public class Foo {

   public override string ToString() {

      return "foo";

   }

}

public class Bar : Foo {

   public override string ToString() {

      return "bar";

   }

}

What is printed out?

Bar b = new Bar ();
Console.WriteLine (b.ToString());

Foo f = b;
Console.WriteLine (f.ToString());

Object o = b;
Console.WriteLine (o.ToString());

 

 

         They all print “bar”. Why?

         Method call virtualizes at runtime

         The static type doesn’t matter

         This is the danger and power of virtual methods

         Danger: Owner of base classes cannot control what subclasses do

         Power: Base class doesn’t have to change as new subclasses are created

Overriding

         Don’t change the semantics of member

         Follow the contract defined on the base class

         Don’t require clients to have knowledge of your overriding

         Consider whether you should call the base implementation

         Favor calling it unless you have good reason not to

 

Virtual and non-virtual

         Use non-virtual members unless you have specifically designed for specialization

         Have a concrete scenario in mind

         Write the code!

         Think before you virtualize members

         Modules that use references to base types must be able to use references to derived types without knowing the difference

         Must continue to call in the same order and frequency

         Cannot increase or decrease range of inputs or output

         See the Liskov Substitution Principle (http://www.brent.worden.org/tips/2000/liskovSubstitutionPrinciple.html)

 

Abstract Members

         Methods, Properties and Events can be abstract

         Use abstract members only where it is absolutely required that subclasses provide a custom implementation

         Only use when the base class cannot have any meaningful default implementation

         Default to making members non-virtual

         Make it virtual if it is designed to be specialized by subclasses

         Make it abstract if no meaningful default implementation is possible

         Unless versioning issues prohibit it, in which case throw a NotImplementedException

 

Interfaces versus Base Classes

         Favor using base classes over interfaces

         Base classes version better in general

         Allows adding members

         Members can be added with a
default implementation

         Avoids incompatibilities common in ActiveX

         Interfaces are good for versioning behavior (changing semantics)

         Avoid having both base class and interfaces

         Adds confusion about which to use

         Component vs. IComponent

         Little advantage

         Consider using Aggregation

         Don’t use attributes where a contract is needed

 

Explicit method implementations

         Implementing members of an interface “privately”

         Not a security boundary!

         Only accessible when cast to the interface type

         Hides implementation details

         Clean public interface

         IConvertible on Int32, etc

         Differentiates implementations

         Simpler strong typing

         The 19 ToXxx methods on IConvertible don’t “pollute” the Int32 public view

         But they are there when cast to IConvertible

         Solution: Implement them privately

public struct Int32 : IConvertible, IComparable {
   public override string ToString () {..}
   int ICovertible.ToInt32 () {..}
   ...
}

int i = 42;
i.ToString();  // works
i.ToInt32();   // does not compile
((IConvertible) i).ToInt32();  // works

 

         Interfaces developed by different groups can have the same signature for different meanings

        Draw() a picture and Draw() a gun

         Frequently you want to differentiate the implementation

         Explicit method implementations enables this

         Avoids us recommending “unique” names in interfaces

interface IGraphics {

   void Draw();

   Brush Brush { get; set; }

   Pen Pen { get; set; }

}

interface IBandit {

   void Draw();

   void Duel(IBandit opponent);

   void Rob(Bank bank, IBandit[] sidekicks);

}

class Bandit: IBandit, IGraphics {

   void IBandit.Draw() {...}

   void IGraphics.Draw() {...}

}

         There is a natural tension between generic typing and strong typing

         List of Object vs. List of Employees

         Generic typing

         Polymorphism

         Strong typing

         More “RAD” experience

         Avoids boxing of value types

         Avoids ugly casts

         Often mutually exclusive

         You can’t have both of these in the same class

         They differ only in return type

This gives you a compile time error

public object this [int index] {

   get{..}  set{..}
}
public string this [int index] {
   get{..} set{..}
}

 

This works:

 

public class StringList : IList
   public string this [int index] {
      get{..} set{..}
   }
   object IList.this [int index] {
      get{..}  set{..}
   }

}

StringList slist = new StringList();
string s1 = slist[0];

IList genList = slist;
string s2 = (string) genList[0];

 

Of course Generics are a better solution