luni, 14 decembrie 2009

[Design Pattern] Bridge Pattern

Bridge Pattern:

The contract can be used as a bridge within other classes, and it allows other classes to consume the concrete implementer without knowing anything about the details.

- separates the contract and implementation in two independent areas.
- use interface in C# to build contracts.
- contract will only provide the functionality.
- contract maintains a reference to an object of type Implementor
- the implementor defines higher-level operations. The implementor's interface doesn't have to correspond exactly to contract's interface

C# Sample:

















/// <summary>
/// ICommunicator is an interface for classes which want to be able to communicate to an collection of <see cref="IImplemetorContract"/>.
/// It has a list of methods that acts on the list of IImplemetorContract objects.
/// </summary>
public interface ICommunicator
{
List<IImplemetorContract> ImplementorsContract { get; }

string GetValues(DateTime i_date);
string GetFullName(int i_index);
void StartGetValues(int i_interval);
void StopGetValues();
}

/// <summary>
/// IImplemetorContract objects act as a bridge to let ICommnucator object consume it.
/// ICommnucator has alist of IImplemetorContract objects with which communicates.
/// It has a list of method which each IImplemetorContract class should implemnt and which should be used by ICommnucator methods
/// </summary>
public interface IImplemetorContract
{
object GetValue(DateTime i_dateTime);
}

/// <summary>
/// A more specific implementator for a Stat
/// </summary>
public interface IStat : IImplemetorContract
{
string Name { get; }
string Caption { get; }
Type Type { get; }
}

/// <summary>
/// Common implementation for all Communicators
/// </summary>
public abstract class AbstractCommunicator
{
private List<IImplemetorContract> m_listImplementorsContract = new List<IImplemetorContract>();
protected Timer _timer = null;
public virtual string GetValues(DateTime i_date)
{
Dictionary<IImplemetorContract, object> _setStatValues = new Dictionary<IImplemetorContract, object>();
StringBuilder _sb = new StringBuilder();
_sb.AppendLine("Communicator: " + GetType().Name + ". Values at time: " + i_date.ToLongTimeString());
foreach (IImplemetorContract _implementor in ImplementorsContract)
{
object _value = _implementor.GetValue(i_date);
_sb.AppendLine(GetFullName(ImplementorsContract.IndexOf(_implementor)) + "\t\t" + _value);
}
return _sb.ToString();
}

public abstract string GetFullName(int i_index);

public List<IImplemetorContract> ImplementorsContract
{
get { return m_listImplementorsContract; }
}

public virtual void StartGetValues(int i_interval)
{
_timer = new Timer(GetValuesNow, null, 1000 , i_interval);
}

public virtual void StopGetValues()
{
if (_timer == null) return;
_timer.Change(Timeout.Infinite, Timeout.Infinite);
_timer.Dispose();
}

protected virtual void GetValuesNow(Object statusInfo)
{
Console.WriteLine(GetValues(DateTime.Now));
}

}

public class CSVCommunicator : AbstractCommunicator, ICommunicator
{
#region ICommunicator Members

public override string GetFullName(int i_index)
{
if (i_index < 0 || i_index > ImplementorsContract.Count - 1)
{
throw new IndexOutOfRangeException();
}
if (ImplementorsContract[i_index] is IStat)
{
return ((IStat)ImplementorsContract[i_index]).Name + "/" + ((IStat)ImplementorsContract[i_index]).Caption;
}
else
{
return ImplementorsContract[i_index].ToString();
}
}

public override void StartGetValues(int i_interval)
{
Console.WriteLine("CSV is writing values");
base.StartGetValues(i_interval);
}

public override void StopGetValues()
{
Console.WriteLine("CSV is stopping writing values");
base.StopGetValues();
}
#endregion
}

public class GuiCommunicator : AbstractCommunicator, ICommunicator
{
#region ICommunicator Members

public override string GetFullName(int i_index)
{
if (i_index < 0 || i_index > ImplementorsContract.Count - 1)
{
throw new IndexOutOfRangeException();
}
if (ImplementorsContract[i_index] is IStat)
{
return ((IStat)ImplementorsContract[i_index]).Caption;
}
else
{
return ImplementorsContract[i_index].ToString();
}
}

public override void StartGetValues(int i_interval)
{
Console.WriteLine("GUI is displaying values");
base.StartGetValues(i_interval);
}

public override void StopGetValues()
{
Console.WriteLine("GUI is stopping displaying values");
base.StopGetValues();
}
#endregion
}
public class DiskFreeSpaceStat : IStat
{
#region IStat Members

public string Name
{
get { return "DiskFreeSpace"; }
}

public string Caption
{
get { return "C Drive Disk Free Space"; }
}

public Type Type
{
get { return typeof(int); }
}

#endregion

#region IImplemetorContract Members

public object GetValue(DateTime i_dateTime)
{
ManagementObject _disk = new ManagementObject("win32_logicaldisk.deviceid=\"c:\"");
_disk.Get();
return _disk["FreeSpace"];
}

#endregion
}

public class DiskLabelStat : IStat
{
#region IStat Members

public string Name
{
get { return "DiskLabel"; }
}

public string Caption
{
get { return "C: Drive Disk Label"; }
}

public Type Type
{
get { return typeof(int); }
}

#endregion

#region IImplemetorContract Members

public object GetValue(DateTime i_dateTime)
{
ManagementObject _disk = new ManagementObject("win32_logicaldisk.deviceid=\"c:\"");
_disk.Get();
return _disk["Name"];

}

#endregion

}

public class DiskSizeStat : IStat
{
#region IStat Members

public string Name
{
get { return "DiskSpace"; }
}

public string Caption
{
get { return "C: Drive Disk Space"; }
}

public Type Type
{
get { return typeof(int); }
}

#endregion

#region IImplemetorContract Members

public object GetValue(DateTime i_dateTime)
{
ManagementObject _disk = new ManagementObject("win32_logicaldisk.deviceid=\"c:\"");
_disk.Get();
return _disk["Size"];

}

#endregion
}

class Program
{
static void Main(string[] args)
{
AppDomain.CurrentDomain.UnhandledException += new UnhandledExceptionEventHandler(CurrentDomain_UnhandledException);
//create communicators
CSVCommunicator CSV = new CSVCommunicator();
GuiCommunicator GUI = new GuiCommunicator();

//create implementors contract
DiskFreeSpaceStat _statFreeSpace = new DiskFreeSpaceStat();
DiskLabelStat _statLabel = new DiskLabelStat();
DiskSizeStat _statDiskSize = new DiskSizeStat();

//CSV communicator is talking with _statDiskSize and _statFreeSpace
Console.WriteLine("\t\tCSV");
CSV.ImplementorsContract.Add(_statDiskSize);
CSV.ImplementorsContract.Add(_statFreeSpace);
Console.WriteLine("First set of values for CSV: \n" + CSV.GetValues(DateTime.Now));
Console.WriteLine();

//GUI communicator is talking with _statDiskSize, _statFreeSpace and _statFreeSpace
Console.WriteLine("\t\tGUI");
GUI.ImplementorsContract.Add(_statDiskSize);
GUI.ImplementorsContract.Add(_statDiskSize);
GUI.ImplementorsContract.Add(_statFreeSpace);
Console.WriteLine("First set of values for GUI: \n" + GUI.GetValues(DateTime.Now));

Console.WriteLine();
Console.WriteLine();

Console.WriteLine("GUI present values at 2 s / CSV is writing value to .csv file at 4 s for 20 s");
GUI.StartGetValues(2000);
CSV.StartGetValues(4000);

AutoResetEvent _autoEvent = new AutoResetEvent(false);

Timer _timer = new Timer(delegate(Object _state)
{
GUI.StopGetValues();
CSV.StopGetValues();
Console.WriteLine("Finishing getting values ");
_autoEvent.Set();
}, null, 20000, 1000);


_autoEvent.WaitOne();
_timer.Dispose();

Console.WriteLine("Bye, bye now. Press ENTER to Finish.");
Console.ReadLine();

}

static void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e)
{
Console.WriteLine(e.ToString());
}
}

Niciun comentariu:

Trimiteți un comentariu