Resolving interfaces at runtime (just before the usage) - c#

Lets say i have the following interface
interface ILeague
{
string ShowSquad();
}
Following classes implementing them
class EPL : ILeague
{
public string ShowSquad()
{
return "EPL players collection";
}
}
class LaLiga: ILeague
{
public string ShowSquad()
{
return "La-liga player Collection";
}
}
i am consuming this interface as shown below
public string ShowLeaguePlayers(ILeague leagueDataProvider)
{
return leagueDataProvider.ShowSquad();
}
Now , depending on the league i am in , i want to show different data. Sometimes EPL and other times LaLiag. This switch can happen with in the same execution cycle.
I tried the following approach
class LeagueDataProvider : ILeague
{
private ILeague m_Provider;
private string league;
private void SetContext()
{
// Have some logic to figure out the league
league = "EPL";
if (league.Equals("EPL"))
{
m_Provider = new EPL();
}
else
{
m_Provider = new LaLiga();
}
}
public string ShowSquad()
{
SetContext();
return m_Provider.ShowSquad();
}
}
I have modified my client code to below
void ShowData()
{
ILeague Dataprovider = new LeagueDataProvider();
Console.WriteLine(ShowLeaguePlayers(Dataprovider));
}
// copied again for easy viewing
public string ShowLeaguePlayers(ILeague leagueDataProvider)
{
return leagueDataProvider.ShowSquad();
}
This works fine , but every time i make a call to ShowSquad , it has to check for the league and fetch the data. Is there a better way to do this ?
What i am trying to achieve here :
Depending on the league , i want to get different data when i call ShowSquad .
I should be able to mock ILeague in UT and in future there might be many more implementations of ILeague so i want to avoid modifying and re-testing components which consume them

Maybe try with the factory pattern :
Interfaces:
interface ILeague
{
string ShowSquad();
}
interface ILeagueFactory
{
ILeague CreateLeague();
}
implementations:
class EPL : ILeague
{
public string ShowSquad()
{
return "EPL players collection";
}
}
class LaLiga: ILeague
{
public string ShowSquad()
{
return "La-liga player Collection";
}
}
class EPLFactory : ILeagueFactory
{
public ILeague CreateLeague()
{
return new EPL();
}
}
class LaLigaFactory : ILeagueFactory
{
public ILeague CreateLeague()
{
return new LaLiga();
}
}
To fetch rigth league factory, you can wrap the factories you need in a collection :
class LeagueFactoryCollection
{
private IDictionary<string, ILeagueFactory> factories;
public LeagueFactoryCollection()
{
factories = new Dictionary<string, ILeagueFactory>();
}
public void Add(string key, ILeagueFactory factory)
{
factories.Add(key, factory);
}
public ILeagueFactory Get(string key)
{
return factories[key];
}
}
Now you should be able to add new League types easier:
//define your needed factories
var leagueCollections = new LeagueFactoryCollection();
leagueCollections.Add("EPL", new EPLFactory());
leagueCollections.Add("LaLiga", new LaLigaFactory());
//consumer
leagueCollections.Get("EPL").CreateLeague().ShowSquad();
Your consumer will not change when you'll add new league

Related

How to enforce method execution order in c#

Long story short, i have following class:
public class FlowBasePipeline<T>
{
private List<StepBaseBusiness<T>> stepList = new List<StepBaseBusiness<T>>();
public void Push(StepBaseBusiness<T> step)
{
stepList.Add(step);
}
public void Trigger(T result)
{
foreach (var step in stepList )
{
result = step.Execute(result);
if (!result.IsSuccess)
{
break;
}
}
}
}
What I'm looking for is forcing programmer to call Push method in the first place and then give them access to Trigger method, in this case following scenario is not allowed
var pipeline=new FlowBasePipeline<MyStepResult>();
pipeline.Trigger()// Trigger method is not recognized
we should first call Push method
var pipeline=new FlowBasePipeline<MyStepResult>();
pipeline.Push(new MyStep()).Trigger()//Now Trigger is recognized
What I've done:
I applied explicit interface method implementation as follows to get it to work:
public interface IBasePipeline<T> where T:BaseResult,new()
{
void Trigger();
IBasePipeline<T> Push(StepBaseBusiness<T> step);
}
public class FlowBasePipeline<T>:IBasePipeline<T> where T:BaseResult,new()
{
private List<StepBaseBusiness<T>> stepList = new List<StepBaseBusiness<T>>();
public IBasePipeline<T> Push(StepBaseBusiness<T> step)
{
stepList.Add(step);
return this;
}
void IBasePipeline<T>.Trigger(T result)
{
foreach (var step in stepList )
{
result = step.Execute(result);
if (!result.IsSuccess)
{
break;
}
}
}
}
Now it works well and we don't have access to Trigger method before Push method, but from my prospective it's not a good way as we might need more level of orders and i don't know how it could be done in this way.
As i know, method chaining is one of the key rules of functional programming.
Is there any pattern or strategy to implement this kind of chaining?
Update:
we need to call push method multiple times
var pipeline=new FlowBasePipeline<MyStepResult>();
pipeline.Push(new MyStep1()).Push(new MyStep2()).Trigger();
After first push, push and trigger would be available.
One way to do this is to use interfaces to restrict access to specific methods by specifying an interface as the result.
public interface IStartCar
{
IDriveCar Start(string key);
}
public interface IDriveCar
{
IParkCar Drive(string address);
}
public interface IParkCar
{
IStopCar Park();
}
public interface IStopCar
{
IParkCar Drive(string address);
void Stop();
}
public class Car : IStartCar, IDriveCar, IParkCar, IStopCar
{
public IDriveCar Start(string key);
public IParkCar Drive(string address);
public IStopCar Park();
public IStopCar Park();
private Car() { }
public static IStartCar Get()
{
var result = new Car();
return result;
}
}
Now to get a Car you use the CarFactory method Get(), it returns a car, but you really only have access to the interface result. This pattern only allows developers to string specific methods together:
var car = Car.Get();
car.Start("key").Drive("address1").Park().Drive("address2").Park().Stop();
Example of approach I use for api's that inherently 'guide' the callers with a fluent syntax:
public class Pipeline
{
readonly List<Action> _steps = new List<Action>();
// only Push is available when Pipeline is initialized
public PipelineWithSteps Push(Action step)
{
_steps.Add(step);
// or cache this if you want 'Push' repeatable
return new PipelineWithSteps(this);
}
public class PipelineWithSteps
{
// not required but often the chained context wants/needs access to the first context
readonly Pipeline _context;
// api is public but ctor cannot be invoked by external caller
internal PipelineWithSteps(Pipeline context) => _context = context;
// now Trigger is available only after something was pushed
public PipelineWithSteps Trigger()
{
foreach(var step in _context._steps)
step();
Console.WriteLine();
return this;
}
// usually I don't repeat an initialization method;
// this could be done using the 'context'
// but would have to be refactored to return the existing 'PipelineWithSteps'
public PipelineWithSteps Push(Action step)
{
_context._steps.Add(step);
return this;
}
}
}
Usage:
var pipeline = new Pipeline();
pipeline.Push(() => Console.WriteLine("A"))
.Push(() => Console.WriteLine("B"))
.Trigger()
.Push(() => Console.WriteLine("C"))
.Trigger();
Output:
A
B
A
B
C
After hours ,i came up with this design:
public interface IBasePipelineRegister<T> where T:BaseResult
{
IStagePipeline<T> Push(StepBaseBusiness<T> step);
List<StepBaseBusiness<T>> Steps { get; set; }
}
public interface IBasePipelineTrigger<T> where T:BaseResult
{
void Trigger(T result);
}
public interface IStagePipeline<T>: IBasePipelineTrigger<T>,IBasePipelineRegister<T> where T:BaseResult
{
}
public class FlowBasePipeline<TResult> : IBasePipelineRegister<TResult> where TResult : BaseResult,new()
{
public List<StepBaseBusiness<TResult>> Steps { get ; set ; }
private IStagePipeline<TResult> _stagePipeline;
public BasePipeline()
{
this.Steps = new List<StepBaseBusiness<TResult>>();
this._stagePipeline = new StagePipeline<TResult>(this);
}
public IStagePipeline<TResult> Push(StepBaseBusiness<TResult> step)
{
Steps.Add(step);
return _stagePipeline;
}
}
As you see, BasePipeline just implements IBasePipelineRegister and Register method presents new StagePipeline class that is consist of current class plus trigger implementation.
public class StagePipeline<T>: IStagePipeline<T> where T:BaseResult
{
private readonly IBasePipelineRegister<T> pipelineRegister;
public List<StepBaseBusiness<T>> Steps { get; set; }
public StagePipeline(IBasePipelineRegister<T> pipelineRegister)
{
this.pipelineRegister = pipelineRegister;
Steps = pipelineRegister.Steps;
}
public IStagePipeline<T> Push(StepBaseBusiness<T> step)
{
return pipelineRegister.Push(step);
}
public void Trigger(T result)
{
foreach (var step in Steps)
{
result = step.Execute(result);
if (!result.IsSuccess)
{
break;
}
}
}
}
Now each method adds a new feature not replacing new one.
var pipeline=new FlowBasePipeline<MyStepResult>();
pipeline.Push(new MyStep1()).Push(new MyStep2()).Trigger();

Unity - Resolve implementation of generic interface based on model type

I'm new to Unity and am running into issues when it comes to classes that implement generic interfaces.
Suppose I have one controller and one service class, with the intention that they call the business layer based on an type identifier passed into the controller. Here's my layout:
Models:
public interface IModel
{
string Name { get; }
}
public class MyOrder : IModel
{
public string Name { get { return "Order"; } }
}
public class MyInvoice : IModel
{
public string Name { get { return "Invoice"; } }
}
Business Logic:
public interface ILogic
{
string GetModelName(IModel myModel);
}
public class MyOrderLogic : ILogic
{
public string GetModelName(IModel myModel)
{
return "MyOrderLogic : " + myModel.Name;
}
}
public class MyInvoiceLogic : ILogic
{
public string GetModelName(IModel myModel)
{
return "MyInvoiceLogic : " + myModel.Name;
}
}
public class LogicFactory
{
Func<IModel, ILogic> logicResolver;
public LogicFactory(Func<IModel, ILogic> resolver)
{
logicResolver = resolver;
}
public ILogic GetLogicForModel(IModel model)
{
return logicResolver(model);
}
}
Service:
public class MySingleService
{
private LogicFactory factory;
public MySingleService(LogicFactory f)
{
this.factory = f;
}
public IModel GetModel(int typeId, int objectId)
{
IModel model;
// This would really call Entity Framework context
switch (typeId)
{
case 1:
model = new MyOrder();
break;
default:
model = new MyInvoice();
break;
}
return model;
}
public void DoSomething(IModel model)
{
var logic = factory.GetLogicForModel(model);
var name = logic.GetModelName(model);
Console.WriteLine(name);
}
}
Controller:
public class MyController
{
MySingleService service;
public MyController(MySingleService s)
{
this.service = s;
}
public void DoAnAction(int typeId, int objectId)
{
var model = service.GetModel(typeId, objectId);
service.DoSomething(model);
}
}
This all works pretty well when I configure my Unity container like so
var container = new UnityContainer();
container.RegisterType<ILogic, MyOrderLogic>("MyOrder");
container.RegisterType<ILogic, MyInvoiceLogic>("MyInvoice");
Func<IModel, ILogic> resolver = (myModel) => container.Resolve<ILogic>(myModel.GetType().Name);
var logicFactory = new LogicFactory(resolver);
container.RegisterInstance<LogicFactory>(logicFactory);
var controller = container.Resolve<MyController>();
My issue is that I want to restrict the Business Logic classes so that they can only work on the proper model (i.e. I want MyOrderLogic to only accept MyOrder)
I wanted to have the business layer make use of generics, like so:
// Business Logic
public interface ILogic<T> where T : IModel
{
string GetModelName(T myModel);
}
public class MyOrderLogic : ILogic<MyOrder>
{
public string GetModelName(MyOrder myModel)
{
return "MyOrderLogic : " + myModel.Name;
}
}
public class MyInvoiceLogic : ILogic<MyInvoice>
{
public string GetModelName(MyInvoice myModel)
{
return "MyInvoiceLogic : " + myModel.Name;
}
}
This caused all kinds of problems between the Service and the Controller. I'm not sure how to properly resolve the *Logic classes based on a type identifier. I tried to do something similar to ILogic<IModel> logic = new MyOrderLogic(), but that obviously didn't work.
Is what I'm looking for possible? Is there something I can add to just the LogicFactory or something?
I want to avoid having individual controller and service objects as they would just have duplicate code.

Appropriate design pattern for the payment modules c#

As i am learning through design pattern concept and also wanted to implement the payment modules in my project using the proper design pattern. So for that I have created some sample code.
Currently I have two concrete implementation for the payment PayPal and Credit Card. But the concrete implementation will be added further on the project.
Payment Service
public interface IPaymentService
{
void MakePayment<T>(T type) where T : class;
}
Credit Card and Pay Pal Service
public class CreditCardPayment : IPaymentService
{
public void MakePayment<T>(T type) where T : class
{
var creditCardModel = (CreditCardModel)(object)type;
//Implementation CreditCardPayment
}
}
class PayPalPayment : IPaymentService
{
public void MakePayment<T>(T type) where T : class
{
var payPalModel = (PayPalModel)(object)type;
//Further Implementation will goes here
}
}
Client Code Implementation
var obj = GetPaymentOption(payType);
obj.MakePayment<PayPalModel>(payPalModel);
Get Payment Option
private static IPaymentService GetPaymentOption(PaymentType paymentType)
{
IPaymentService paymentService = null;
switch (paymentType)
{
case PaymentType.PayPalPayment:
paymentService = new PayPalPayment();
break;
case PaymentType.CreditCardPayment:
paymentService = new CreditCardPayment();
break;
default:
break;
}
return paymentService;
}
I thought of implementing this modules using strategy design pattern, and I got deviated from Strategy and ended up doing this way.
Is this a proper way for creating the payment modules. Is there a more better approach of solving this scenario. Is this a design pattern?
Edited:
Client Code:
static void Main(string[] args)
{
PaymentStrategy paymentStrategy = null;
paymentStrategy = new PaymentStrategy(GetPaymentOption((PaymentType)1));
paymentStrategy.Pay<PayPalModel>(new PayPalModel() { UserName = "", Password = "" });
paymentStrategy = new PaymentStrategy(GetPaymentOption((PaymentType)2));
paymentStrategy.Pay<CreditCardModel>(
new CreditCardModel()
{
CardHolderName = "Aakash"
});
Console.ReadLine();
}
Strategy:
public class PaymentStrategy
{
private readonly IPaymentService paymentService;
public PaymentStrategy(IPaymentService paymentService)
{
this.paymentService = paymentService;
}
public void Pay<T>(T type) where T : class
{
paymentService.MakePayment(type);
}
}
Does this update inlines with the Strategy Pattern?
One major drawback of using an abstract factory for this is the fact that it contains a switch case statement. That inherently means if you want to add a payment service, you have to update the code in the factory class. This is a violation of the Open-Closed Principal which states that entities should be open for extension but closed for modification.
Note that using an Enum to switch between payment providers is also problematic for the same reason. This means that the list of services would have to change every time a payment service is added or removed. Even worse, a payment service can be removed from the strategy, but still be an Enum symbol for it even though it isn't valid.
On the other hand, using a strategy pattern doesn't require a switch case statement. As a result, there are no changes to existing classes when you add or remove a payment service. This, and the fact that the number of payment options will likely be capped at a small double-digit number makes the strategy pattern a better fit for this scenario.
Interfaces
// Empty interface just to ensure that we get a compile
// error if we pass a model that does not belong to our
// payment system.
public interface IPaymentModel { }
public interface IPaymentService
{
void MakePayment<T>(T model) where T : IPaymentModel;
bool AppliesTo(Type provider);
}
public interface IPaymentStrategy
{
void MakePayment<T>(T model) where T : IPaymentModel;
}
Models
public class CreditCardModel : IPaymentModel
{
public string CardHolderName { get; set; }
public string CardNumber { get; set; }
public int ExpirtationMonth { get; set; }
public int ExpirationYear { get; set; }
}
public class PayPalModel : IPaymentModel
{
public string UserName { get; set; }
public string Password { get; set; }
}
Payment Service Abstraction
Here is an abstract class that is used to hide the ugly details of casting to the concrete model type from the IPaymentService implementations.
public abstract class PaymentService<TModel> : IPaymentService
where TModel : IPaymentModel
{
public virtual bool AppliesTo(Type provider)
{
return typeof(TModel).Equals(provider);
}
public void MakePayment<T>(T model) where T : IPaymentModel
{
MakePayment((TModel)(object)model);
}
protected abstract void MakePayment(TModel model);
}
Payment Service Implementations
public class CreditCardPayment : PaymentService<CreditCardModel>
{
protected override void MakePayment(CreditCardModel model)
{
//Implementation CreditCardPayment
}
}
public class PayPalPayment : PaymentService<PayPalModel>
{
protected override void MakePayment(PayPalModel model)
{
//Implementation PayPalPayment
}
}
Payment Strategy
Here is the class that ties it all together. Its main purpose is to provide the selection functionality of the payment service based on the type of model passed. But unlike other examples here, it loosely couples the IPaymentService implementations so they are not directly referenced here. This means without changing the design, payment providers can be added or removed.
public class PaymentStrategy : IPaymentStrategy
{
private readonly IEnumerable<IPaymentService> paymentServices;
public PaymentStrategy(IEnumerable<IPaymentService> paymentServices)
{
this.paymentServices = paymentServices ?? throw new ArgumentNullException(nameof(paymentServices));
}
public void MakePayment<T>(T model) where T : IPaymentModel
{
GetPaymentService(model).MakePayment(model);
}
private IPaymentService GetPaymentService<T>(T model) where T : IPaymentModel
{
var result = paymentServices.FirstOrDefault(p => p.AppliesTo(model.GetType()));
if (result == null)
{
throw new InvalidOperationException(
$"Payment service for {model.GetType().ToString()} not registered.");
}
return result;
}
}
Usage
// I am showing this in code, but you would normally
// do this with your DI container in your composition
// root, and the instance would be created by injecting
// it somewhere.
var paymentStrategy = new PaymentStrategy(
new IPaymentService[]
{
new CreditCardPayment(), // <-- inject any dependencies here
new PayPalPayment() // <-- inject any dependencies here
});
// Then once it is injected, you simply do this...
var cc = new CreditCardModel() { CardHolderName = "Bob" /* Set other properties... */ };
paymentStrategy.MakePayment(cc);
// Or this...
var pp = new PayPalModel() { UserName = "Bob" /* Set other properties... */ };
paymentStrategy.MakePayment(pp);
Additional References:
Dependency Injection Unity - Conditional Resolving
Factory method with DI and IoC
This is one approach you could take. There's not a lot to go on from your source, and I'd really reconsider having MakePayment a void instead of something like an IPayResult.
public interface IPayModel { } // Worth investigating into common shared methods and properties for this
public interface IPaymentService
{
void MakePayment(IPayModel payModel);
}
public interface IPaymentService<T> : IPaymentService where T : IPayModel
{
void MakePayment(T payModel); // Void here? Is the status of the payment saved on the concrete pay model? Why not an IPayResult?
}
public class CreditCardModel : IPayModel
{
public string CardHolderName { get; set; }
}
public class PayPalModel : IPayModel
{
public string UserName { get; set; }
public string Password { get; set; }
}
public class CreditCardPayment : IPaymentService<CreditCardModel>
{
public void MakePayment(CreditCardModel payModel)
{
//Implmentation CreditCardPayment
}
void IPaymentService.MakePayment(IPayModel payModel)
{
MakePayment(payModel as CreditCardModel);
}
}
public class PayPalPayment : IPaymentService<PayPalModel>
{
public void MakePayment(PayPalModel payModel)
{
//Implmentation PayPalPayment
}
void IPaymentService.MakePayment(IPayModel payModel)
{
MakePayment(payModel as PayPalModel);
}
}
public enum PaymentType
{
PayPalPayment = 1,
CreditCardPayment = 2
}
So following your implementation approach, it could look something like:
static class Program
{
static void Main(object[] args)
{
IPaymentService paymentStrategy = null;
paymentStrategy = GetPaymentOption((PaymentType)1);
paymentStrategy.MakePayment(new PayPalModel { UserName = "", Password = "" });
paymentStrategy = GetPaymentOption((PaymentType)2);
paymentStrategy.MakePayment(new CreditCardModel { CardHolderName = "Aakash" });
Console.ReadLine();
}
private static IPaymentService GetPaymentOption(PaymentType paymentType)
{
switch (paymentType)
{
case PaymentType.PayPalPayment:
return new PayPalPayment();
case PaymentType.CreditCardPayment:
return new CreditCardPayment();
default:
throw new NotSupportedException($"Payment Type '{paymentType.ToString()}' Not Supported");
}
}
}
I also think for a strategy/factory pattern approach, manually creating an IPayModel type doesn't make much sense. Therefore you could expand the IPaymentService as an IPayModel factory:
public interface IPaymentService
{
IPayModel CreatePayModel();
void MakePayment(IPayModel payModel);
}
public interface IPaymentService<T> : IPaymentService where T : IPayModel
{
new T CreatePayModel();
void MakePayment(T payModel);
}
public class CreditCardPayment : IPaymentService<CreditCardModel>
{
public CreditCardModel CreatePayModel()
{
return new CreditCardModel();
}
public void MakePayment(CreditCardModel payModel)
{
//Implmentation CreditCardPayment
}
IPayModel IPaymentService.CreatePayModel()
{
return CreatePayModel();
}
void IPaymentService.MakePayment(IPayModel payModel)
{
MakePayment(payModel as CreditCardModel);
}
}
Usage would then be:
IPaymentService paymentStrategy = null;
paymentStrategy = GetPaymentOption((PaymentType)1);
var payModel = (PayPalModel)paymentStrategy.CreatePayModel();
payModel.UserName = "";
payModel.Password = "";
paymentStrategy.MakePayment(payModel);
Your code is basically using the factory pattern. This is a good way to handle more than one method of payment
http://www.dotnettricks.com/learn/designpatterns/factory-method-design-pattern-dotnet

Add object which does not implement interface, but meets all qualifications, to a list expecting interface

I have the following:
List<IReport> myList = new List<IReport>();
Report myReport = TheirApi.GetReport();
myReport meets all the qualifications of IReport, but cannot implement IReport because I do not have access to the source of TheirApi. Casting to type IReport obviously results in null, and I read that I cannot cast an anonymous type to an interface.
Do I have any options here?
A wrapper class was just what the doctor ordered:
ReportServices.GetAllCustomReports().ToList().ForEach(customReport => _customReports.Add(new ReportWrapper(customReport)));
public class ReportWrapper : IReport
{
private Report inner;
public int ID
{
get { return inner.ID; }
set { inner.ID = value; }
}
public string Name
{
get { return inner.Name; }
set { inner.Name = value; }
}
public ReportWrapper(Report obj)
{
inner = obj;
}
}
You will need to wrap this object inside another one that implements the interface, and then you will need to implement it calling the inner object's properties and methods.
For example:
public class ReportWrapper : IReport
{
MyObjectIsLikeReport inner;
public ReportWrapper(MyObjectIsLikeReport obj) {
this.inner = obj;
}
public void ReportMethod(int value) {
this.inner.ReportMethod(value);
}
public int SomeProperty {
get { return this.inner.SomeProperty; }
set { this.inner.SomeProperty = value; }
}
}
To use it, you can do this:
List<IReport> myList = new List<IReport>();
MyObjectIsLikeReport myReport = TheirApi.GetReport();
myList.Add(new ReportWrapper(myReport));
Consider Adapter Design Pattern.
Definition: Convert the interface of a class into another interface
clients expect. Adapter lets classes work together that couldn't
otherwise because of incompatible interfaces.
good reference: http://www.dofactory.com/Patterns/PatternAdapter.aspx
interface IReport
{
void DoSomething();
}
class ReportApdapter : IReport
{
private readonly Report _report;
public ReportApdapter(Report report)
{
_report = report;
}
public void DoSomething()
{
_report.DoSomething();
}
}
class Report
{
public void DoSomething()
{
}
}
//You can use like this.
IReport report = new ReportApdapter(TheirApi.GetReport());

How to change the class of an object dynamically in C#?

Suppose I have a base class named Visitor, and it has 2 subclass Subscriber and NonSubscriber.
At first a visitor is start off from a NonSubscriber, i.e.
NonSubscriber mary = new NonSubscriber();
Then later on this "mary" subscribed to some services, and I want to change the type of "mary" to Subscriber.
What is the conventional way to do that?
can't do that. sorry. C# is not a dynamic language.
You will have to create a new mary = new Subscriber(); and copy all relevant properties.
But a better approach might be to model it differently: Give Visitor a list of subscriptions. An empty list means a NonSubscriber.
You cant do this type of conversion.
What you should do is treat mary as a visitor, and when time arrives, create a new instance of "subscriber":
Visitor mary = new NonSubscriber();
// Do some Visitor operations
...
// Now mary is a Subscriber
mary = new Subscriber();
You could use the GOF design patterns State or Strategy to model such an behaviour. Using these patterns, it seems during runtime as if the class of the objects has been changed.
It seems that you have some design problems. I think that it would be better to redesign your code like:
class Visitor
{
private bool isSubscriber = false;
public bool IsSubscriber
{
get { return isSubscriber; }
}
public void Subscribe()
{
// do some subscribing stuff
isSubscriber = true;
}
public void Unsubscribe()
{
// do some unsubscribing stuff
isSubscriber = false;
}
}
You cannot change the type of a variable at runtime. You need to create a new instance.
mary = new Subscriber();
Create a Subscriber constructor that takes a NonSubscriber object as a parameter, or create a method on the NonSubscriber object that returns a Subscriber to save you having to writer the mappping code in multiple places.
It seems like you are encoding information incorrectly into your class hierarchy. It would make more sense to use a different pattern than sub classing here. For example, use only one class (visitor, or perhaps you could name it potential subscriber, whatever seems appropriate) and encode information on the services the object is subscribed to, moving the dynamically changing behavior behind a "Strategy" pattern or some such. There's very little detail in your example, but one thing you could do in C# is to make a "subscriber" property which would change the behavior of the object when the state of the property was changed.
Here's a contrived somewhat related example:
class Price
{
private int priceInCents;
private bool displayCents;
private Func<string> displayFunction;
public Price(int dollars, int cents)
{
priceInCents = dollars*100 + cents;
DisplayCents = true;
}
public bool DisplayCents
{
get { return displayCents; }
set
{
displayCents = value;
if (displayCents)
{
this.displayFunction = () => String.Format("{0}.{1}", priceInCents / 100, priceInCents % 100);
}
else
{
this.displayFunction = () => (priceInCents / 100).ToString();
}
}
}
public string ToString()
{
return this.displayFunction();
}
}
public class User
{
public Subscription Subscription { get; set; }
public void HandleSubscription()
{
Subscription.Method();
}
}
public abstract class SubscriptionType
{
public abstract void Method();
}
public class NoSubscription : SubscriptionType
{
public override void Method()
{
// Do stuff for non subscribers
}
}
public class ServiceSubscription : SubscriptionType
{
public override void Method()
{
// Do stuff for service subscribers
}
}
public class Service2Subscription : SubscriptionType
{
public override void Method()
{
// Do stuff for service2 subscribers
}
}
Think the code explains my answer :)
Adding to the other answers and your comment, you indeed can use the state pattern for your purpose, it would go something like this:
public class MyProgram
{
public void Run()
{
Visitor v = new Visitor("Mary");
Debug.Assert(v.SubscriptionLinkText == "Join now");
v.IsSubscribed = true;
Debug.Assert(v.SubscriptionLinkText == "Today's special");
v.IsSubscribed = false;
Debug.Assert(v.SubscriptionLinkText == "Join now");
}
}
public class Visitor
{
public string Name { get; set; }
private bool _isSubscribed;
public bool IsSubscribed
{
get { return this._isSubscribed; }
set
{
if (value != this._isSubscribed)
{
this._isSubscribed = value;
this.OnSubscriptionChanged();
}
}
}
private SubscriptionBase _subscription;
public string SubscriptionLinkText
{
get { return this._subscription.LinkText; }
}
public Visitor(string name)
{
this.Name = name;
this._isSubscribed = false;
this.OnSubscriptionChanged();
}
private void OnSubscriptionChanged()
{
// Consider also defining an event and raising it here
this._subscription =
SubscriptionBase.GetSubscription(this.IsSubscribed);
}
}
abstract public class SubscriptionBase
{
// Factory method to get instance
static public SubscriptionBase GetSubscription(bool isSubscribed)
{
return isSubscribed ?
new Subscription() as SubscriptionBase
: new NoSubscription() as SubscriptionBase;
}
abstract public string LinkText { get; }
}
public class Subscription : SubscriptionBase
{
public override string LinkText
{
get { return "Today's Special"; }
}
}
public class NoSubscription : SubscriptionBase
{
public override string LinkText
{
get { return "Join now"; }
}
}

Categories

Resources