A strategy is a specific procedure for accomplishing a goal. The goal itself is expressed as an interface. The interface separates the consumer of the goal from its various implementations. By replacing the implementation, you can change the behavior of the system.

The term strategy may be too lofty for the concept. It's really more like a recipe. The goal is to make a meal, but if you substitute the Fettuccini Alfredo recipe with Chicken Cordon Bleu, the result will be quite different.

There are several ways of replacing strategies. Most common implementations are based on dependency injection. You can pass a strategy object to its consumer, perhaps in its constructor.

But an equally valid implementation is to use generics. Add a constraint that the type placeholder implements an interface. Because the consumer of the strategy needs to create an instance, you also need the default constructor constraint. Provide a concrete strategy type when you want to call the consumer.

Public Interface ILockingStrategy

    Sub Lock()
    Sub Unlock()

End Interface

Public Class MyLockableObject _
    (Of LockingStrategy As _
        {ILockingStrategy, New})

    Private _lockingStrategy As _
        New LockingStrategy

    Public Sub BeginUse()
        _lockingStrategy.Lock()
    End Sub

    Public Sub EndUse()
        _lockingStrategy.Unlock()
    End Sub

End Class

public interface ILockingStrategy
{
    void Lock();
    void Unlock();
}

public class MyLockableObject
        <LockingStrategy>
    where LockingStrategy :
        ILockingStrategy, new()
{
    private LockingStrategy _lockingStrategy
        = new LockingStrategy();

    public void BeginUse()
    {
        _lockingStrategy.Lock();
    }

    public void EndUse()
    {
        _lockingStrategy.Unlock();
    }
}

The advantage of generics for this pattern is that the code is declarative. Instead of procedurally creating a strategy and handing it off, you declare that the consumer uses a specific strategy. This makes the code match the intent a little more closely.

The disadvantage of a generic implementation is that strategies cannot be chosen at run time. Generics are a compile-time construct, so they must be completely satisfied before the program runs. If you need to change strategies on-the-fly, use a more traditional dependency-injection approach.