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
Related
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
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.
One of my interfaces has a string property that will depend on where the interface is being used. I want to avoid hardcoding the property every time the object is created. I can set the property in constructor, but the object is injected using a factory.
The interface as follows:
public interface IObjectStore
{
string StorageTableName { get; set;}
void UpdateObjectStore(string key, string value);
string ReadObjectStore(string key);
}
Which is used in a service
public class CategoryService<T> : ICategoryService<T> where T : Company
{
private readonly IObjectStore objectStore;
public CategoryService(IObjectStore objStore)
{
this.objectStore = objStore;
objectStore.StorageTableName = "CategoryTable"; // I want to avoid this hard coding
}
...
}
The service is created using service factory (Ninject.Extensions.Factory)
public interface IServiceFactory
{
ICategoryService<T> CreateCategoryService<T>() where T : class;
}
Which is then injected using Ninject at the controller level. Here are my bindings
bool storeInNoSql = true;
kernel.Bind<IServiceFactory>().ToFactory().InSingletonScope();
kernel.Bind<ICategoryService<Article>>().To<CategoryService<Article>>();
kernel.Bind<IObjectStore>().ToMethod(ctx => storeInNoSql ? ctx.Kernel.Get<ObjectStore>() : null);
So the question is: how do i tell Ninject to set the property StorageTableName to "CategoryTable" everytime the object is injected into CategoryService and to "ArticleTable" everytime it is inserted into ArticleService?
I think this is what you are looking for.
It's just a very small sample project I just did, but this should solve your problem.
public class Ninject_34091099
{
public static void Run()
{
using (IKernel kernel = new StandardKernel())
{
kernel.Bind<IInterface<Generic1>>()
.To<Class<Generic1>>()
.WithConstructorArgument("name", "STRING ONE");
kernel.Bind<IInterface<Generic2>>()
.To<Class<Generic2>>()
.WithConstructorArgument("name", "The other string");
kernel.Bind<IServiceFactory>().ToFactory().InSingletonScope();
var factory = kernel.Get<IServiceFactory>();
var c1 = factory.CreateInterface<Generic1>();
var c2 = factory.CreateInterface<Generic2>();
Console.WriteLine(c1.Name);
Console.WriteLine(c2.Name);
}
Console.WriteLine("Done");
Console.ReadLine();
}
}
public interface IInterface<T> where T : class
{
string Name { get; set; }
}
public class Generic1
{
}
public class Generic2
{
}
public class Class<T> : IInterface<T> where T : class
{
public string Name { get; set; }
public Class(string name)
{
Name = name;
}
}
public interface IServiceFactory
{
IInterface<T> CreateInterface<T>() where T : class;
}
Sorry that the names mean nothing :D
Hope it helps
I frequently seems to come up to a situation where I have an abstract type which needs to be processed differently depending on which concrete implementation it has.
As an example, an abstract class Payment could be subclassed as class CreditCard or class StoredCredit. To actually process the payment, we want to use an implementation of
interface IPaymentTaker {
PaymentProcessingResult Process(Payment payment); }
i.e. either
class CreditCardPaymentTaker : IPaymentTaker { ... }
or
class StoredCreditPaymentTaker : IPaymentTaker { ... }
In the past I have injected an IDictionary into the parent component and then done
_paymentTakers[payment.GetType()].Process(payment);
The downside of this is that the IPaymentTaker implementations are not strongly typed enough, so the first bit of the Process method has to be:
Process(Payment payment)
{
var creditCardPayment = payment as CreditCardPayment;
if (creditCardPayment == null)
throw new Exception("Payment must be of type CreditCard");
}
I'm sure there must be a name for the pattern I'm trying to implement but I don't know what it is!
Ideally I would
(a) be able to instantiate the PaymentProcessor based just on the type of the Payment, without creating the dictionary;
(b) be able to have strongly typed PaymentProcessors that only accept the subclass they can use.
Does anyone have a neat way of solving this problem?
You can solve this with a visitor:
interface IPaymentVisitor {
void Visit(CreditCard payment);
void Visit(StoredCredit payment);
}
abstract class Payment {
public abstract void Accept(IPaymentVisitor visitor);
}
class CreditCard : Payment {
public override void Accept(IPaymentVisitor visitor) {
visitor.Visit(this);
}
}
class StoredCredit : Payment {
public override void Accept(IPaymentVisitor visitor) {
visitor.Visit(this);
}
}
class PaymentTaker : IPaymentVisitor, IPaymentTaker {
public void Visit(CreditCard payment) {
// ...
}
public void Visit(StoredCredit payment) {
// ...
}
public PaymentProcessingResult Process(Payment payment) {
payment.Accept(this);
// ...
}
}
If you still want to separate the different payment takers, or if your hierarchy jitters, you can use an acyclic visitor (pdf):
interface IPaymentVisitor {
}
interface IPaymentVisitor<TPayment> : IPaymentVisitor where TPayment : Payment {
void Visit(TPayment payment);
}
abstract class Payment {
public abstract void Accept(IPaymentVisitor visitor);
}
class CreditCard : Payment {
public override void Accept(IPaymentVisitor visitor) {
if (visitor is IPaymentVisitor<CreditCard>) {
((IPaymentVisitor<CreditCard>)visitor).Visit(this);
}
}
}
class StoredCredit : Payment {
public override void Accept(IPaymentVisitor visitor) {
if (visitor is IPaymentVisitor<StoredCredit>) {
((IPaymentVisitor<StoredCredit>)visitor).Visit(this);
}
}
}
class CreditCardPaymentTaker : IPaymentVisitor<CreditCard>, IPaymentTaker {
public void Visit(CreditCard payment) {
// ...
}
public PaymentProcessingResult Process(Payment payment) {
payment.Accept(this);
// ...
}
}
class StoredCreditPaymentTaker : IPaymentVisitor<StoredCredit>, IPaymentTaker {
public void Visit(StoredCredit payment) {
// ...
}
public PaymentProcessingResult Process(Payment payment) {
payment.Accept(this);
// ...
}
}
interface IPayment
{
IPaymentTaker Taker {get;}
}
class CreditCardPayment : IPayment
{
IPaymentTaker Taker{ get {return new CreditCardPaymentTaker();}}
}
payment.Taker.Process(payment);
Even though James' method is ideal, using an IoC container could be difficult. Here's my Reflection or dynamics based approach. Doing the following will allow you to still use an IoC to setup the mapping between the PaymentTaker and Payment.
public class Payment
{
}
public class CreditCardPayment : Payment
{
}
public class StoreCreditPayment : Payment
{
}
public interface IPaymentTaker
{
}
public interface IPaymentTaker<T> : IPaymentTaker
{
void Process(T payment);
}
public static class PaymentTaker
{
public static void Process(Payment payment)
{
var paymentType = payment.GetType();
// You would have these already setup and loaded via your IOC container...
var paymentTakers = new Dictionary<Type, IPaymentTaker>();
paymentTakers.Add(typeof(CreditCardPayment), new CreditCardPaymentTaker());
paymentTakers.Add(typeof(StoreCreditPayment), new StoreCreditPaymentTaker());
// Get the payment taker for the specific payment type.
var paymentTaker = paymentTakers[paymentType];
// Execute the 'Process' method.
paymentTaker.GetType().GetMethod("Process").Invoke(paymentTaker, new object[]{ payment });
// If .NET 4.0 - dynamics can be used.
// dynamic paymentTaker = paymentTakers[paymentType];
// paymentTaker.Process((dynamic)payment);
}
}
public class CreditCardPaymentTaker : IPaymentTaker<CreditCardPayment>
{
public void Process(CreditCardPayment payment)
{
Console.WriteLine("Process Credit Card Payment...");
}
}
public class StoreCreditPaymentTaker : IPaymentTaker<StoreCreditPayment>
{
public void Process(StoreCreditPayment payment)
{
Console.WriteLine("Process Credit Card Payment...");
}
}
And then you can use it like this:
var cc = new CreditCardPayment();
PaymentTaker.Process(cc);
If you can ensure the names of the Payment and PaymentTaker match you can use something like this:
Process(Payment payment)
{
String typeName = "YourPathToPaymentTakers." + payment.GetType().Name + "Taker";
Type type = typeof(IPaymentTaker).Assembly.GetType(typeName);
IPaymentTaker taker = (IPaymentTaker)Activator.CreateInstance(type);;
}
I have used this approach in the past, but if you do not have 100% control of the names of the classes this could be a problem.
Is there any issues in using version 2,to get the same results as version 1.
Or is this just bad coding.
Any Ideas
public class Customer
{
public int CustomerID { get; set; }
public string EmailAddress { get; set; }
int Age { get; set; }
}
public interface ICustomer
{
void AddNewCustomer(Customer Customer);
void AddNewCustomer(string EmailAddress, int Age);
void RemoveCustomer(Customer Customer);
}
public class BALCustomer
{
private readonly ICustomer dalCustomer;
public BALCustomer(ICustomer dalCustomer)
{
this.dalCustomer = dalCustomer;
}
public void Add_A_New_Customer(Customer Customer)
{
dalCustomer.AddNewCustomer(Customer);
}
public void Remove_A_Existing_Customer(Customer Customer)
{
dalCustomer.RemoveCustomer(Customer);
}
}
public class CustomerDataAccess : ICustomer
{
public void AddNewCustomer(Customer Customer)
{
// MAKE DB CONNECTION AND EXECUTE
throw new NotImplementedException();
}
public void AddNewCustomer(string EmailAddress, int Age)
{
// MAKE DB CONNECTION AND EXECUTE
throw new NotImplementedException();
}
public void RemoveCustomer(Customer Customer)
{
// MAKE DB CONNECTION AND EXECUTE
throw new NotImplementedException();
}
}
// VERSION 2
public class Customer_New : DataRespository<CustomerDataAccess>
{
public int CustomerID { get; set; }
public string EmailAddress { get; set; }
public int Age { get; set; }
}
public class DataRespository<T>
where T:class,new()
{
private T item = new T();
public T Execute { get { return item; } set { item = value; } }
public void Update()
{
//TO BE CODED
}
public void Save()
{
//TO BE CODED
}
public void Remove()
{
//TO BE CODED
}
}
class Program
{
static void Main(string[] args)
{
Customer_New cus = new Customer_New()
{
Age = 10,
EmailAddress = "this#demo.com"
};
cus.Save();
cus.Execute.RemoveCustomer(new Customer());
// Repository Version
Customer customer = new Customer()
{
EmailAddress = "new#demo.com",
CustomerID = 10
};
BALCustomer bal = new BALCustomer(new CustomerDataAccess());
bal.Add_A_New_Customer(customer);
}
}
You have a lot of things going on that aren't making a lot of sense.
First of all, the names of properties should always be a noun (singular or plural) or a "being" verb like Is* or Has*. These are properties of an object, and should be similar to what you would say in response to a question like "Would you please describe your desk?" Execute is an operation, and should therefore be a method. Likewise, your naming conventions in Version 1 should be PascalCased which means no underscores and the first letter of all words should be capitalized. These aren't die-hard truths, but they are considered OOP common C# coding standards.
Secondly, the code in your main method isn't actually implementing anything in your generic class. The only thing your class is actually doing is creating an instance of CustomerDataAccess. The Save() method won't do anything, unless you specifically are able to call item.Save() In order to use your Save, Update, Delete functionality on your generic class, your CustomerDataAccess class will have to implement an interface expected by your generic class. For instance:
public interface IDataAccess<T> : where T : YourBaseObject {
public void Update(T item);
public void Save(T item);
public void Remove(T item);
}
public class Customer : YourBaseObject {
public int CustomerID { get; set; }
public string EmailAddress { get; set; }
public int Age { get; set; }
}
public class CustomerDataAccess :
DataRespository<IDataAccess<Customer>> {
public void PerformCustomerOnlyAction(Customer customer) {
/* do stuff */
}
}
Now, you can create a generic class that handles basic CRUD functionality, and all other functionality is accessible through the BaseRepository property.
/* e.g. T = IDataAccess<Customer>, K = Customer */
public class DataRespository<T>
where T : IDataAccess<K>, new()
where K : YourBaseObject, new()
{
private T _base;
public T BaseRepository {
get {
if(_base == null)
_base = Activator.CreateInstance<T>();
return _base;
}
}
public void Update(K item) { /* functionality for YourBaseObject */ }
public void Save(K item) { /* functionality for YourBaseObject */ }
public void Remove(K item) { /* functionality for YourBaseObject */ }
}
class Program
{
static void Main(string[] args)
{
var repository = new CustomerDataAccess();
Customer c = new Customer {
Age = 10,
EmailAddress = "this#demo.com"
};
repository.Save(c);
// This pass-through is no longer needed, but shown as example
// repository.BaseRepository.PerformCustomerOnlyAction(c);
repository.PerformCustomerOnlyAction(c);
}
}
NOTE I did the above code from scratch/memory. The generic type constraints may not work exactly as I have them.
ASP.NET 3.5 Unleashed by Stephen Walther has a couple of chapters on creating a repository pattern which is setup similarly to what you're trying to accomplish in Version 2. He also splits processing up between a business logic layer and a data access layer. Although the book is huge (nearly 2000 pages) and many of the code examples are redundant or better left as part of the CD, he goes pretty in-depth for beginner-to-intermediate range. It's available used on Amazon for around $25.
I think while implementing object model of your application you just have to ask yourself a number of questions as though you are make object design review of your collegue code.
Why CustomerAccessLayer implements interface? Is there will be a number of layers implementing this Interface. Or maybe you are expecting any polymorph behaviour from classes implements this interface? Or maybe you will separate interface to standalone module and will provide its functionality though any kind of service?
Why do you need BALCustomer class? Why you could not make calls directly to CustomerAccesLayer? And, have i already spoke about codesyle? :)
If DataRepository have a generic behaviour and will provide a number of AccessLayers throw Execute property why it is have its own methods?
I think could be continued... I hope you've catch my point?