Here is the design problem in pseudo example:
It is ASP.NET User control (UC) which uses the "Food" object as data source and this object has property FoodType - "Veg" || "Nonveg".
The user control changes UI display depending upon FoodType property. In code-behind class of User Control, some methods have same if/then/else condition: if(Food.FoodType == "Veg")... else ...
Here, I would like use State-like pattern such that code-behind class of User Control will contain two inner/nested classes, i.e. "VegFood" class and "NonvegFood" class. Now, lets say, NonvegFood class will contain its own logic implementation.
But having one interface, two instance classes (as nested) which will be used in this user control only, could be overdesign. In addition to that, UC does not have driver method where I can call related methods in one if block, like they are "DataBound" and "ItemCreated".
Still, is it possible to have State like pattern inside UC class? Probably two instance inner classes inside UC and somehow if I can delegate call to one of these inner class?
class UC : UserControl
{
class VegFood
{
string DisplayName
{
get
{
return "Rice";
}
}
}
class NonvegFood
{
string DisplayName
{
get
{
return "Chicken";
}
}
}
protected string DisplayName
{
get
{
return Instance.DisplayName;
}
}
/*********** MAGIC Property ****************/
private ? Instance
{
get
{
return ?;
}
}
}
I do not think that having three nested classes is not design overkill if it makes the code easier to maintain.
I would suggest an abstract base State class which defines the contract of your states. Each state would inherit from this.
Extended your code sample:
class UC : UserControl
{
protected string DisplayName
{
get
{
return Instance.DisplayName;
}
}
/*********** MAGIC Property ****************/
private FoodState _instance = null;
private FoodState Instance
{
get
{
if (_instance == null)
{
if (FoodType == "Veg")
{
_instance = new VegFood();
}
else
{
_instance = new NonvegFood();
}
}
return _instance;
}
}
abstract class FoodState
{
abstract public string DisplayName {get;}
}
class VegFood : FoodState
{
public string DisplayName
{
get
{
return "Rice";
}
}
}
class NonvegFood : FoodState
{
public string DisplayName
{
get
{
return "Chicken";
}
}
}
}
You probably don't need the protected DisplayName property on the UserControl directly, as Instance.DisplayName could be used directly by the aspx page.
Related
I've made a class with T. It looks like this.
public interface ISendLogic<T> where T : NarcoticsResult
{
ChangeType Change_New();
ChangeType Change_Cancel();
PurchaseType Purchase_New();
PurchaseType Purchase_Cancel();
}
public class SendLogic<T> : ISendLogic<T> where T : NarcoticsResult
{
private eReportType _type;
private bool Send_Change()
{
// Send to server by xml file
}
private bool Send_Purchase()
{
// Send to server by xml file
}
public ChangeType Change_New()
{
_type = change_new;
Send_Change();
}
public ChangeType Change_Cancel()
{
_type = change_cancel;
Send_Change();
}
public PurchaseType Purchase_New()
{
_type = purchase_new;
Send_Purchase();
}
public PurchaseType Purchase_Cancel()
{
_type = purchase_cancel;
Send_Purchase();
}
}
There are two types, ChangeType and PurchaseType
and these are inherited from NarcoticsResult.
I thought the person who want to use this class would use it like this.
// this class can only be used when someone wants to use change function
var logic = SendLogic<ChangeType >();
logic.Change_New();
logic.Change_Cancel();
Here is a question.
I want to force this class to be used only as I thought.
I mean, I want to prevent it to be used like this.
var logic = SendLogic<ChangeType>();
logic.Change_New(); // OK
logic.Purchase_New(); // You should make this class like SendLogic<PurchaseType>()
I thought I add some code which check type of T in every function.
How do you think the way I thought. I think there are better way to fix it
Please tell me a better way
thank you.
Personally, I don't think you need a generic class in this case. What you need is either an abstract base class or an interface. I personally love the interface approach as below:
public interface ISendLogic {
void New();
void Cancel();
}
So now you've got a contract that will force the consumer of your code to use New or Cancel methods only.
The next step you can implement that send logic interface for your specific implementation:
public class ChangeSendLogic : ISendLogic {
private eReportType _type;
public ChangeSendLogic(
/*you can put the necessary parameters in the constructor
and keep it as private fields in the object*/
)
{
}
private bool Send_Change()
{
// Send to server by xml file
}
public void New()
{
_type = change_new;
Send_Change();
}
public void Cancel()
{
_type = change_cancel;
Send_Change();
}
}
public class PurchaseSendLogic : ISendLogic {
private eReportType _type;
public PurchaseSendLogic(
/*you can put the necessary parameters in the constructor
and keep it as private fields in the object*/
)
{
}
private bool Send_Purchase()
{
// Send to server by xml file
}
public void New()
{
_type = change_new;
Send_Purchase();
}
public void Cancel()
{
_type = change_cancel;
Send_Purchase();
}
}
From here you can see those two classes handle the implementation for each type nicely. You can think this is as an implementation of single responsibility principle. So if you have one more type, you can just add one more implementation of this interface rather than updating the existing classes.
If you want to hide the creation of those objects, in the next part you can introduce a kind of factory or selector as below:
public enum SendLogicType {
Change,
Purchase
}
public static SendLogicSelector {
public static ISendLogic GetSendLogic(SendLogicType type)
{
switch(type)
{
case SendLogicType.Change:
return new ChangeSendLogic();
case SendLogicType.Purchase:
return new PurchaseSendLogic();
}
}
}
This is how the code will be consumed:
ISendLogic sendLogic = SendLogicSelector.GetSendLogic(SendLogicType.Change);
sendLogic.New(); // change new logic executed
sendLogic.Cancel(); // change cancel logic executed
sendLogic = SendLogicSelector.GetSendLogic(SendLogicType.Purchase);
sendLogic.New(); // purchase new logic executed
sendLogic.Cancel(); // purchase cancel logic executed
Hopefully, you can get the idea of my approach. Good luck! :)
Thank you for your comment
I divided it into two parts like below
public class ChangeSendLogic : SendLogic<ChangeType>, IChangeLogic
public class PurchaseSendLogic : SendLogic<PurchaseType>, IPurchaseLogic
And I also divided interface too
public interface IChangeLogic
{
ChangeType Change_New();
ChangeType Change_Cancel();
}
public interface IPurchaseLogic
{
PurchaseType Purchase_New();
PurchaseType Purchase_Cancel();
}
And I made SendLogic<T> class to abstract class.
This is because I want to make the person who wants to use this class to use a class that inherits from this class without directly accessing it.
Thank you for your comment. I got a good idea.
I am working on a C# project and I need to manage a local cache of data and present it on a GUI.
For example I have:
public class DataFromOtherLibrary
Now I want make a class to help translate the information I need out of it
public class MyDataModel
{
private DataFromOtherLibrary cache;
public MyDataModel ( DataFromOtherLibrary Source)
{
cache = Source;
}
public long Field1 { get { return cache.SomeField; } }
public long Field2 { get { return cache.OtherFiled; } }
}
Now the issue I have is I need to create a MyDataModel for every DataFromOtherLibrary it would be nice to have a single translator class. I'm not sure how to do it and still implement properties (which I need to data-bind to).
Thanks
Matt
You should use a Provider with all your DataModels in it Like:
public class MyDataModelProvider
{
public List<MyDataModel> DataModelList { get; set; }
MyDataModelProvider()
{
loadDataModelList();
}
private void LoadDataModel()
{
foreach (Cachobject c in Cache)
{
this.DataModelList.Add(new MyDataModel(c.valueA,c.valueB));
}
}
}
and for this Provider you also need a Factory Like:
[Singleton(true)]
public class DataModelListProviderFactory
{
private static DataModelListProvider dataListProvider;
public DataModelListProvider getInstance()
{
if (dataListProvider == null)
{
dataListProvider = new DataModelListProvider();
return dataListProvider;
}
else
return dataListProvider;
}
}
Because now you have a single Spot with all your DataModels and you only must recieve them once. You can also easily search the List for a specific Model if you have a case or you show all the Data in a View.
You can read here more about Factory Patterns.
Hope that helps.
I have several UserControls that are sharing some common properties. Example:
private List<MyObject> Sample
{
get
{
return Session["MyObject"] as List<MyObject>;
}
set
{
Session["MyObject"] = value;
}
}
I want to share this to all user controls inside my project. (Not to other projects in a solution, of course). What I'm trying to do is create a separate class and inherit from that class. Something like:
public class SampleBase : Web.UI.UserControl
{
protected List<MyObject> Sample
{
get
{
return Session["MyObject"] as List<MyObject>;
}
set
{
Session["MyObject"] = value;
}
}
}
And then my control can inherit those values by deriving from that class:
partial class myControl : SampleBase
One problem I encounter is that I cannot derive from base if control already has something inherited:
partial class myControl : SomethingELSE
Otherwise it works fine, but I'm not sure if it is a good approach and I'm looking for suggestions.
If my understanding is correct, you only want to get rid of the inheritance hierarchy of your User Controls
Another approach would be using Extension Methods
For example:
Interface to mark your USerControls
public interface IMyUserControlMark { }
Extensions
public static class MyUserClassExtensions
{
public static List<object> GetSampleData(this IMyUserControlMark myUserControl)
{
if (HttpContext.Current.Session["MyObject"] == null)
{
return Enumerable.Empty<object>().ToList();
}
return HttpContext.Current.Session["MyObject"] as List<object>;
}
public static void SetSampleData(this IMyUserControlMark myUserControl, List<object> myObject)
{
HttpContext.Current.Session["MyObject"] = myObject;
}
}
User control
public partial class Content1 : System.Web.UI.UserControl, IMyUserControlMark
{
...
}
public partial class Content2 : System.Web.UI.UserControl, IMyUserControlMark
{
....
}
Now you will be able to call your extension methods from within your UserControl or from the ASPX code behind like this:
From the UserControl
var myObject = this.GetSampleData();
this.SetSampleData(myObject);
From the ASPX code behind
var myObject = this.uc1.GetSampleData();
this.uc1.SetSampleData(myObject);
This is a classic example where you need to "favor composition over inheritance".
Instead of inheriting from the class, you hold a reference to an instance of the class. Then you provide simple pass-through code to access the methods/properties of the class.
So, for your example:
public class SomeBehavior
{
public List<MyObject> Sample
{
get { return Session["MyObject"] as List<MyObject>; }
set { Session["MyObject"] = value; }
}
}
public class MyControl : UserControl
{
private SomeBehavior _someBehavior;
public MyControl()
{
_someBehavior = new SomeBehavior();
}
public List<MyObject> Sample
{
get { return _someBehavior.Sample; }
set { _someBehavior.Sample = value; }
}
}
Another option is to allow access to the behavior class directly:
public class MyControl : UserControl
{
public SomeBehavior SomeBehavior { get; private set; }
public MyControl()
{
SomeBehavior = new SomeBehavior();
}
}
The advantage of this is that you don't have to write the pass-through code. The disadvantage is that it violates the Law of Demeter, which says that you should "only talk to your immediate friends". If you do it this way, other classes that use MyControl need to know about SomeBehavior. Following the Law Of Demeter can improve maintainability and adaptability of your code, but it comes at a cost of lots of pass-through code.
Apart from previous solutions, maybe it's time for applying some MVC/MVP pattern?
For web forms there is a great framework called WebFormsMVP: link
In the library there is a mechanism called Cross Presenter Messaging thanks to which you can share a data between your controls using the publish/subscribe pattern.
For better explanation look here and here
I suggest to give the library a chance :)
In C# you can inherit from only one class and implement multiple interfaces.
This is allowed:
partial class myControl : SampleBase
partial class myControl : SampleBase, Interface1
partial class myControl : SampleBase, Interface1, Interface2, Interface3
This is NOT allowed:
partial class myControl : SomethingELSE, SampleBase
Try making SomethingELSE inherit from SampleBase if it satisfies your design. If not, then I suggest encapsulating SampleBase as a property of each control that needs it as it also suggested #DanM.
If I try "var mainpage new Mainpage()"
I will run the mainpage constructor and then all the fields in the XAML object will return to null. How to I access XAML objects in silverlight that are from a different class but part of the same namespace?
Let me explain by example. If you look at the first answer, here is what I am encountering
public class MyPage
{
MyPage()
{
// the constructor makes all the variables from the xaml null
}
public TextBox MyTextBox
{
get { return SomeTextBox; }
}
}
public class SomeOtherClass
{
private void SomeFunction()
{
var page = new MyPage(); // this makes the text empty
var sometext = page.MyTextBox.Text; // so sometext will be empty
}
}
So whatever the user imputs when the program first runs turns to null when I run SomeFunction.
What I am first going to try is to see if when SomeClass is created, the values are put into that class.
If that fails, I am going to try MVVM. I have seen the http://www.vimeo.com/8915487 video and I got the sample mvvm code
Here is the Model:
namespace SimpleMVVM.Model
{
public class SimpleModel
{
// super easy version
//public string SomeSimpleValue { get; set; }
private string _SomeSimpleValue = string.Empty;
// actually do something version...
public string SomeSimpleValue
{
get
{
return "some value";
}
set
{
_SomeSimpleValue = value;
}
}
}
}
here is the view:
and here is the viewmodel.cs
using Simple;
using SimpleMVVM.Model;
namespace SimpleMVVM.ViewModel
{
public class SimpleViewModel : SimpleViewModelBase
{
private SimpleModel MyModel = new SimpleModel();
public string SomeSimpleValue
{
get { return MyModel.SomeSimpleValue; }
set
{
if (MyModel.SomeSimpleValue != value)
{
MyModel.SomeSimpleValue = value;
RaisePropertyChanged("SomeSimpleValue");
}
}
}
}
}
Using this example, I am wondering if it will just as easy as injecting a ViewModel and then changing the bindings in the Model and the View.
Is MVVM really this easy?
There is one more. It is the viewmodel base class
using System.ComponentModel;
namespace Simple
{
public class SimpleViewModelBase : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
public void RaisePropertyChanged(string PropertyName)
{
var e = new PropertyChangedEventArgs(PropertyName);
PropertyChangedEventHandler changed = PropertyChanged;
if (changed != null) changed(this, e);
}
}
}
OK, so now the hard part. If I create a new class. How do I get the data from the viewmodel class?
First, let me get this rant out of the way: what you propose is very bad design. It fits the definition of smelly code.
If you insist on doing it this way, the "best" approach to take is to declare some public variables on your page that return the actual UI elements.
<UserControl x:Class="MyNamespace.MyPage" ...>
<Grid>
<TextBox x:Name="SomeTextBox" Width="100" />
</Grid>
</UserControl>
public class MyPage
{
public TextBox MyTextBox
{
get { return SomeTextBox; }
}
}
public class SomeOtherClass
{
private void SomeFunction()
{
var page = new MyPage();
page.MyTextBox.Text = "some text";
}
}
Of course the preferred method would be to use something like the MVVM pattern to implement binding from your window to its viewmodel, then you can just read the property values from the viewmodel, this way you avoid trying to touch any UI elements from a totally different class.
Another way to do it (without going the full MVVM route) is to inject the necessary values into the constructor of the control/page that you are instantiating, and from there you can assign them to the appropriate UI element properties. This is still smelly, but better than directly accessing the UI elements from the outside.
I have a main object which has some properties and methods. This object can have multiple parts. These parts are required. The amount of these parts is variable.
Each part has different properties and is referenced to the main object.
To accomplish this in my GUI I have a tabcontrol. The first tab is the main object. The other tabs describes the main object further. These 'other' tabs are the parts I mentioned above.
I am trying to design an architecture, but I can't figure I hope yoy can help me.
As suggested from the answers, the part-tabs inherit from an interface. But how does the main know about it's parts? The parts can't be hardcoded because it is variable. To hardcode the parts is a violation of the OCP principle.
Also, when loading the main object, again, how does it knows about it parts? I have to 'register' them somewhere, but where?
Create interface for your parts, that can have reference to main object. And main object will contain collection of parts as Collection<IPart>
class MainObject
{
Collection<IPart> Parts {get;set;}
}
interface IPart
{
MainObject MainObject {get;set;}
}
class SomePartImpl : IPart
{
//properties of this IPart implementation
}
This classes is entities. Your data service must implement logic for saving and cascade operations.
Sample wcf service(from my project):
[EnableClientAccess]
public class ModelService : LinqToEntitiesDomainService<dpirtEntities>
{
public void InsertZone(Zone zone)
{
if ((zone.EntityState != EntityState.Detached))
{
this.ObjectContext.ObjectStateManager.ChangeObjectState(zone, EntityState.Added);
}
else
{
this.ObjectContext.Zones.AddObject(zone);
}
}
public void UpdateZone(Zone currentZone)
{
Zone originalZone = this.ChangeSet.GetOriginal(currentZone);
if ((currentZone.EntityState == EntityState.Detached))
{
if (originalZone != null)
{
this.ObjectContext.Zones.AttachAsModified(currentZone, originalZone);
}
else
{
this.ObjectContext.Zones.Attach(currentZone);
}
}
foreach (Document doc in this.ChangeSet.GetAssociatedChanges(currentZone, o => o.Documents))
{
ChangeOperation op = this.ChangeSet.GetChangeOperation(doc);
switch (op)
{
case ChangeOperation.Insert:
if ((doc.EntityState != EntityState.Added))
{
if ((doc.EntityState != EntityState.Detached))
{
this.ObjectContext.ObjectStateManager.ChangeObjectState(doc, EntityState.Added);
}
else
{
this.ObjectContext.AddToDocuments(doc);
}
}
break;
case ChangeOperation.Update:
this.ObjectContext.Documents.AttachAsModified(doc, this.ChangeSet.GetOriginal(doc));
break;
case ChangeOperation.Delete:
if (doc.EntityState == EntityState.Detached)
{
this.ObjectContext.Attach(doc);
}
this.ObjectContext.DeleteObject(doc);
break;
case ChangeOperation.None:
break;
default:
break;
}
}
}
public void DeleteZone(Zone zone)
{
if ((zone.EntityState == EntityState.Detached))
{
this.ObjectContext.Zones.Attach(zone);
}
this.ObjectContext.Zones.DeleteObject(zone);
}
}
Have a List or Dictionary in your Main class and store the references to the different objects.
For example:
All the tabs implement an interface called IScreenTab.
class MainTab : IScreenTab
{
// Store a map of scree name to screen object
// You can also just use a List<IScreenTab>
private Dictionary<string, IScreenTab> m_OtherScreens;
// Your implementation goes here
public MainTab(){ }
public MainTab(List<IScreenTab> screenTabList){ }
public AddTab(string screenName, IScreenTab screenTabObj){ }
}
I've done something similar in the past, and I decoupled my GUI from my domain design by using an IoC container. In my code I used StructureMap, which was very easy to adopt.
I had exactly the same setup in which there was an 'editor' which contained a number of 'tabs'. Each tab could either contain some different view of my 'object' or it could show an item from collections stored within the 'object'. So there were a number of static and variable tabs.
So, I needed two things.
1. A way to create an editor, with the correct number of tabs.
2. A way to create the tab, plus all it's controls.
So, I created an interface for each, which looked loosely like this.
public interface IEditorFactory<TObject>
{
Editor CreateEditor(TObject instance);
}
public interface ITabEditorFactory<TObject>
{
void CreateTab(TObject instance, Editor parent);
}
I'll leave Editor up to your imagination. By in my app it was a custom UserControl, with various features and behaviour.
Next, imagine we had a Person, who had personal info, an Address an multiple contracts.
public class Person
{
public string Title { get; set; }
public string Forename { get; set; }
public string Surname { get; set; }
public string EmployeeNumber { get; set; }
public string NationalInsuranceNumber { get; set; }
public Address Address { get; set; }
public IEnumerable<Contract> Contracts { get; }
}
My app wanted to display one 'Personal Details' tab, one 'Employment' tab, one 'Address' tab and multiple 'Contract' tabs.
I implemented the following.
public class PersonalTab : ITabEditorFactory { ... }
public class EmployeeTab : ITabEditorFactory { ... }
public class AddressTab : ITabEditorFactory { ... }
public class ContractTab : ITabEditorFactory { ... }
Notice how #1 and #2 implement the same ITabEditorFactory. That's because they both display different aspects of the Person.
But before I had implemented those I implemented the PersonEditor
public class PersonEditor : IEditorFactory { ... }
It was good that I implemented this first, as it forced de-coupling my editor factory from all the tab factories. I wouldn't accidentally slip in any references to concrete classes. My editor factory just knew how to ask for a ITabEditorFactory<> for the Person, Address and Contract classes.
My final solution was a little more complicated than I outlined above, as it also covered Editor re-use for different instances, how to handle multiple (or no) tab editors for any a single class, and being able to define security on a tab-by-tab basis.
The end result was that I had a GUI model that was decoupled from my domain, and was extensible without requiring me to change a single line of existing code.
Lovely jubbly.