Skip to content

Instantly share code, notes, and snippets.

@bestknighter
Last active June 11, 2022 04:44
Show Gist options
  • Save bestknighter/8e70499ea4a3194dcd3a3d66b80e1f3a to your computer and use it in GitHub Desktop.
Save bestknighter/8e70499ea4a3194dcd3a3d66b80e1f3a to your computer and use it in GitHub Desktop.
Structure (with example) for a Model <-> Viewer inspired code architecture
using System;
public class Program
{
public static void Main()
{
var fc = new MyIntViewer_FancyConsole();
var sc = new MyIntViewer_SimpleConsole();
Console.WriteLine("Hello World");
var x = new MyInt();
Console.WriteLine("Initial value: "+x.Value);
x.Value = 2;
x.Bind( new[]{fc} );
x.Value = 10;
x.Bind( new[]{sc} );
x.Value = -26;
x.Value = int.MaxValue;
x.Unbind( new[]{fc} );
x.Value = int.MinValue;
x.Value = 0;
x.Value = 2022;
x.Unbind( new[]{sc} );
x.Value += 100;
x.Value -= 2022;
x.Bind( new MyIntViewer[]{fc, sc} );
x.Value += 100;
x.Value = 42;
x.UnbindAll();
x.Value = 1;
x.Value = 0;
}
}
/** Model example
* Here I created a simple one for demonstration purposes.
* But this can get as complex as you desire. For example,
* I used this structure for making different inventory
* viewers for a single inventory in a Unity game I worked on.
* Items had all sorts of information that most viewers didn't
* care about. So I simply updated them when needed and passing
* only what was truly needed.
*/
using System.Collections.Generic;
public class MyInt : Viewable<MyInt, MyIntViewer>
{
private int _value = 0;
public int Value
{
get { return _value; }
set
{
foreach( var v in m_viewers ) v.ValueWillChange(value);
_value = value;
}
}
readonly private List<MyIntViewer> m_viewers = new List<MyIntViewer>();
// If it makes no sense for a model to have more than one viewer, it can be handled in the function.
// You can ignore or throw or do whatever you deem fit.
public void Bind(MyIntViewer[] viewers)
{
foreach(var v in viewers)
{
if( !m_viewers.Contains(v) )
{
v.Bind(this);
m_viewers.Add(v);
}
}
}
public void Unbind(MyIntViewer[] viewers)
{
foreach(var v in viewers)
{
var idx = m_viewers.FindIndex(mv => mv == v);
if( idx != -1 )
{
m_viewers[idx].Unbind();
m_viewers.RemoveAt(idx);
}
}
}
public void UnbindAll()
{
foreach(var v in m_viewers) v.Unbind();
m_viewers.Clear();
}
}
public interface Viewable<TViewable, TViewer>
where TViewable: class, Viewable<TViewable, TViewer>
where TViewer:Viewer<TViewer, TViewable>
{
void Bind(TViewer[] viewers);
void Unbind(TViewer[] viewers);
void UnbindAll();
}
public abstract class Viewer<TViewer, TViewable>
where TViewable: class, Viewable<TViewable, TViewer>
where TViewer: Viewer<TViewer, TViewable>
{
protected TViewable model = null;
public bool Bind(TViewable model)
{
if( this.model != null ) Unbind();
this.model = model;
return OnBind();
}
public void Unbind()
{
OnUnbind();
model = null;
}
protected abstract bool OnBind();
protected abstract void OnUnbind();
}
/** You can declare a concrete class if there's no need for different viewers.
* Or you can declare an abstract class like below if you want different viewers.
* You can have several types of Viewers this way. Console, file logger, GUI, remote computer, etc.
*/
using System;
public abstract class MyIntViewer : Viewer<MyIntViewer, MyInt>
{
protected override bool OnBind()
{
Console.WriteLine("I just got binded! :D");
return true;
}
protected override void OnUnbind()
{
Console.WriteLine("I was unbinded... :(");
}
abstract public void ValueWillChange(int newValue);
}
public class MyIntViewer_SimpleConsole : MyIntViewer
{
override public void ValueWillChange(int newValue)
{
Console.WriteLine(DateTime.Now.ToUniversalTime().ToString()+"\t-\tOld: "+model?.Value+"\tNew: "+newValue);
}
}
public class MyIntViewer_FancyConsole : MyIntViewer
{
override public void ValueWillChange(int newValue)
{
Console.WriteLine("Sir, I detected a change on the value I was watching. It used to be "+model.Value
+" and now its new value is "+newValue);
}
}
@bestknighter
Copy link
Author

bestknighter commented Jun 10, 2022

Output:

Hello World
Initial value: 0
I just got binded! :D
Sir, I detected a change on the value I was watching. It used to be 2 and now its new value is 10
I just got binded! :D
Sir, I detected a change on the value I was watching. It used to be 10 and now its new value is -26
06/11/2022 04:36:18    -    Old: 10    New: -26
Sir, I detected a change on the value I was watching. It used to be -26 and now its new value is 2147483647
06/11/2022 04:36:18    -    Old: -26    New: 2147483647
I was unbinded... :(
06/11/2022 04:36:18    -    Old: 2147483647    New: -2147483648
06/11/2022 04:36:18    -    Old: -2147483648    New: 0
06/11/2022 04:36:18    -    Old: 0    New: 2022
I was unbinded... :(
I just got binded! :D
I just got binded! :D
Sir, I detected a change on the value I was watching. It used to be 100 and now its new value is 200
06/11/2022 04:36:18    -    Old: 100    New: 200
Sir, I detected a change on the value I was watching. It used to be 200 and now its new value is 42
06/11/2022 04:36:18    -    Old: 200    New: 42
I was unbinded... :(
I was unbinded... :(

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment