オブジェクト思考のキモを体感するには

このエントリーを読んで。
突破すると一気に学習が加速する「オブジェクト指向学習の壁」を突破する鍵となる知識を、中学生でも分かるように図解してみた(初学者向け) - @fromdusktildawnの本館

「壁」を突破できたと思ったのは、デコレーターパターンとコマンドパターンを実際に使いこなせる様になった時でしょうか。
対象のエントリーでは、優しく図解していることが逆にややこしくなっている気がする。(矢印大杉)

個人的経験から言うとロギング関係クラスをお題にしてオブジェクト指向を説明すると受け入れてもらえることが多かったです。
たとえば、下記のILoggerを実装するクラスたちは利用方法が統一されているため、実装の詳細関係なくロガーとしては同じように使用することができます。これがポリモーフィズムと呼ばれるものです。また、ILogger型の値として各ロガーを扱うこともできます。
(この話題より前のクラス、オブジェクト、メソッドというのは参考書などを読めば理解できるはず。これが理解できないとお話にならないと言わざる得ない。)

これらをさらに拡張して、ログレベルによるフィルタリングを行うようなデコレーターやスレッドセーフ対応を行うためのデコレーターなどを作ることで
実際に体感できるかなと。

//ロガーインターフェイス
interface ILogger
{
  //ログ書き込みをする際に呼び出すメソッド名とパラメーターを定義
  void WriteLog(string msg);
}

//標準出力へログ出力
class ConsoleLogger : ILogger
{
  void WriteLog(string msg){
    System.Console.WriteLine(msg);
  }
}

//指定ファイルへログ出力
class FileLogger : ILogger
{
  private string filePath;

  public FileLogger(string filePath){
    this.filePath = filePath;
  }

  void WriteLog(string msg){
    //ファイルをオープンし、そこへ書き込む
    using(var fs = new FileStream(filePath)){
      fs.WriteLine(msg);
    }
  }
}

//複数のロガーをまとめて使用する。
class MultiLogger : ILogger
{
  private List<ILogger> loggers = new List<ILogger>();

  public void Add(ILogger logger){
    loggers.Add(logger);
  }

  void WriteLog(string msg){
    for(var i=0;i<loggers.Count;i++){
      loggers[i].WriteLine(msg);
    }
  }
}

//使用方法
class Program
{
  static void Main(string[] args){
    //ConsoleLoggerもFileLoggerもILoggerの実装クラスなため、ILogger型変数に代入することができる。
    //(ただしインターフェイスで定義されている操作のみ呼び出し可能)
    ILogger logger = new ConsoleLogger();
    logger.WriteLog("標準出力へログ出力");
    logger = new FileLogger("c:\access.log");
    logger.WriteLog("ファイルへログ出力");

    //MultiLogger.Addメソッドの引数はILogger型。このインターフェイス実装クラスであれば、
    //実装の詳細関係なくロガーとして引き渡すことができる。
    MultiLogger multiLogger = new MultiLogger();
    multiLogger.Add(new ConsoleLogger());
    multiLogger.Add(new FileLogger("c:\access.log"));
    //ConsoleLogger、FileLoggerに "ログ出力!!!" と出力される。
    mlogger.WriteLog("ログ出力!!!");
  }
}