I have two derived classes (Sale and ServiceCharge). Both are Transactions. If I have a BusinessService, I want to create a ServiceCharge for it. If I pass a Product, I want to instantiate Sale.
Here's my idea.
private void CreateInstance(object element)
{
Transaction transaction;
if (element.GetType() == typeof(BussinessService))
{
transaction = new ServiceCharge((BussinessService)element))
}
else
{
transaction = new Sale((Product)element);
}
{
Could you tell me a more elegant way? I would know how to use generics with only a single constructor
private void CreateInstance<T>(T element)
{
Transaction transaction = new Transaction((T)element);
}
But I don't know how to work out with the first case.
Just a plain interface would also work in this case:
interface ITransactionable
{
Transaction CreateTransaction();
}
class BusinessService : ITransactionable
{
public Transaction CreateTransaction() { return new ServiceCharge( this ); }
}
class Product : ITransactionable
{
public Transaction CreateTransaction() { return new Sale( this ); }
}
private void CreateInstance(ITransactionable element)
{
Transaction transaction = element.CreateTransaction();
...
}
Define a generic interface like this:
public interface ITransactionable<T>
where T : Transaction
{
T CreateTransaction();
}
And decorate your BussinessService and Product as:
public class BussinessService :
ITransactionable<ServiceCharge>
{
public T CreateTransaction()
{
return new ServiceCharge(this);
}
}
public class Product :
ITransactionable<Sale>
{
public T CreateTransaction()
{
return new Sale(this);
}
}
Now your generic method can be defined as:
private void CreateInstance<T>(ITransactionable<T> element)
{
Transaction transaction = element.CreateTransaction();
...
}
Just create two different methods:
private void CreateInstance(Product product)
{
Transaction transaction = new Sale(product);
}
private void CreateInstance(BusinessService service)
{
Transaction transaction = new ServiceCharge(service);
}
The compiler will know what method you called depending on the type of the parameter you use.
BusinessService and Product should be polymorphic in some way, probably by sharing a interface, somthing like
interface IChargable<out T> where T : Transaction
{
Transaction Charge();
}
The interface implemented thus,
class BusinessService : IChargable<ServiceCharge>
{
public ServiceCharge Charge()
{
return new ServiceCharge(...
}
}
class Product : IChargable<Sale>
{
public Sale Charge()
{
return new Sale(...
}
}
which means some code like this would work
var chargables = new IChargable<Transaction>[]
{
new BusinessService(),
new Product()
};
var transactions = chargables.Select(c => c.Charge());
Related
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();
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
Is it possible to limit object creation to methods of specific class?
For exemple: I have a class Transaction, and I would like to limit it object creation to methods of any class that inherits from AbstractService or IService:
Allowed Scenario:
public class ServiceA : AbstractService (or IService)
{
public void MethodA()
{
var transaction = new Transaction();
}
public void MethodB()
{
var transaction = new Transaction();
}
}
Prohibited Scenario:
public class ServiceB
{
public void MethodA()
{
var transaction = new Transaction(); // cannot create
}
public void MethodB()
{
var transaction = new Transaction(); // cannot create
}
}
There is a access modifier or something else that I can mount that scenarios?
There is a access modifier or something else that I can mount that scenarios?
Yes there is something else that can "mount" that scenario, but it's a lot of work and abstraction for, in my opinion, very little reward. This requires returning an interface of the Transaction, not a concrete type. (I'm pretty sure this works, I haven't compiled it however).
public abstract class AbstractService
{
}
public interface IService
{
}
public interface ITransaction
{
}
public static class TransactionFactory
{
// created them as extensions, but you could remove *this*
public static ITransaction CreateTransaction(this AbstractService instance)
{
return new Transaction ();
}
public static ITransaction CreateTransaction(this IService instance)
{
return new Transaction ();
}
private class Transaction : ITransaction
{
public Transaction ()
{
}
}
}
As a side note, someone technically could pass in null, so it would be best to do additional checking of the method parameters (however, that would be a runtime issue instead of a compile time issue).
If you wanted compile time checking I think you could do...
public interface ITransactionFactory { }
public abstract class AbstractService : ITransactionFactory { }
public interface IService : ITransactionFactory { }
public static class TransactionFactory<T>
where T : ITransactionFactory
{
public static ITransaction CreateTransaction(this T instance)
{
return new Transaction ();
}
// ....
Not quite sure if the second one works
The short answer is no, there is no access modifier which says "This object can only be constructed from a class which implements a specific interface".
You could code your way round this limitation, but its far from clean/foolproof.
public class Transaction
{
private Transaction(){} // private important!
public static Transaction Create(object creator)
{
if(creator is IService)
return new Transaction();
throw new InvalidOperationException();
}
}
public class ServiceA : IService
{
public void MethodA()
{
var transaction = Transaction.Create(this); // works
}
}
public class ServiceB
{
public void MethodA()
{
var transaction = Transaction.Create(this); // fails
}
}
It should be obvious how easily circumventable the above is. I suspect you have an XY Problem and you think this was the way to solve it.
Maybe I'm misunderstanding what you're trying to do, but it seems like this should do the trick:
public abstract class AbstractService : IService
{
protected class Transaction
{
}
}
public class ServiceA : AbstractService
{
public void MethodA()
{
var transaction = new Transaction();
}
public void MethodB()
{
var transaction = new Transaction();
}
}
public class ServiceB
{
public void MethodA()
{
var transaction = new Transaction(); // cannot create
}
public void MethodB()
{
var transaction = new Transaction(); // cannot create
}
}
internal interface IService
{
}
If you want anyone else to be able to use the Transaction, you'll need to have it implement some public interface or inherit it from another public class, but you can now ensure that no one else can create a Transaction object.
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());
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"; }
}
}