Delphi Design Patterns

Delphi Design Patterns

Marco Cantù

 

We have some interesting IDE builds floating around… Marco’s title bar says “Borland Developer Studio 2010”. At one point when he was having some problems with the IDE, he said, “Well, it’s an early beta.”

 

  • What is a pattern?
  • Sample GoF patterns
    • Implemented with some creativity
    • Applied to “everyday visual” code
  • Delphi 2006 and patterns

Goals of this talk

  • Overview of patterns in OOP
  • Explore a number of classic patterns from the GoF book
    • from the Delphi language perspective (which matters – some of the creational patterns, for example, aren’t necessary in Delphi)
    • providing some implementation samples

What are patterns?

  • Capture similarities in repeated building blocks: design solutions, not actual code
  • GoF book
  • Pattern layout: name, problem, solution, consequences
    • The code is there as a hint, not very important. These are design patterns, not code patterns.

Goals of Patterns

  • Better OOP
    • Many patterns promote loose coupling -> more flexibility
    • “Think before you code” approach
  • Better communication
    • Pattern names are very relevant
  • RAD shines but…
    • As apps grow, you need a better infrastructure, not just the plain VCL

Prototype pattern

  • Create a new object of the same kind of another object you have at hand
  • In Delphi you can implement a Prototype using:
    • Class references
      • If you don’t need to copy the data, you can just do Object.ClassType.Create
      • If you want to call the right virtual constructor, you need to cast: TComponentClass(C.ClassType).Create(C.Owner)
    • Streaming
      • AStream.WriteComponentRes(C.Name, C);
      • Create a new instance, then AStream.ReadComponentRes(C); (but if both have the same owner, watch out for Name collisions)
    • RTTI
      • RegisterClass[es] the classes you’re going to use
      • Then you can write a Clone method

Singleton pattern

  • Only one instance of a class
  • Very simple pattern, but very tricky to implement
    • Needs a specific setup mechanism
      • Or can you use a constructor as well?
    • Consider subclasses
      • Data in unit causes some trouble

Adapter pattern

  • Convert the interface of a class into another expected by the user of the class
  • Better than “if X is…”
  • Can be nicely implemented using interfaces
  • Examples:
    • Descend from visual controls, so you can add e.g. “Text” and “Value” properties to  multiple different controls.
    • Interposer class: descendant class that has the same name as the base class. Interesting way to force the runtime to create *your* TButton instead of the standard TButton. Yikes. (Seems like that would be really brittle! The compiler wouldn’t even tell you if you got it wrong.) (It would also be problematic in .NET, if both are in the same namespace.)

Façade pattern

  • Provide a simpler, higher-level interface to a set of interfaces in a subsystem, making it simpler to use and promoting weak coupling
  • In Delphi: a single interface for a collection of components hosted by a container (e.g., providing access to the field values of a dataset on a data module)
  • Shield you from the other guy’s implementation details (at least a little)

Flyweight

  • Replace a series of many objects with a single stateless one, with status information provided on method invocation: pretend you’ve created 10,000 of something
  • The DbCtrlGrid is the perfect example. It looks like it’s got many editors, but in reality it’s only got two

Proxy pattern (Marco writes it as “proxi”)

  • Provide a surrogate (placeholder) for an object (delaying creation cost, if any)
  • Delphi uses something like this for form handles, different reason (that reason being Windows 9x)
  • At design time, a proxy is created for the form you’re editing
  • Proxy components as “light” representations of components (e.g., a database table). Increases total memory usage if you do need to create everything, but decreases time and memory if you don’t.
  • Proxies in OPF frameworks
    • Lightweight objects with few DB columns

Iterator pattern

  • Provide a way to access the elements of an aggregate object sequentially, without exposing its underlying representation
  • Often used with container classes
  • Are iterators better than for loops on VCL lists?
    • Probably
    • The new “for..in” loop is an out-of-the-box implementation of the Iterator pattern

Observer pattern

  • Define a one-to-many dependency between objects, so that when one object changes state, all its dependents are notified of this
  • One of Marco’s favorites, found in the VCL
    • Notification and notification subscription
    • DataSource (a broker that sits between the two ends, and manages the notifications)
    • Actions (I don’t think these are really Observer, since they’re “pull” rather than “push”)
  • Example: a MultiCast event handler
    • Eww, his “MultiClick” is a write-only property. Worse, setting it doesn’t replace the old value of the property – it accumulates. And magically ignores duplicates. None of which is intention-revealing. Very smelly code.
  • A “Real” Observer: demo

Delphi 2006 and Patterns

  • Available with Together support
  • GoF patterns implementations
  • Extensible with your own patterns

Leave a Reply

Your email address will not be published. Required fields are marked *