So we have a class that does needs to output the result of an operation. Now this was tightly-coupled to emails, however with dependency injection I thought I could add more persistence options, eg. save to disk.
The problem is that saving to disk requires a path, while 'saving' as an email requires other details (from, to, etc).
Is this something that can be achieved through dependency injection? Or am I doing the whole thing wrong? Check code below and my comments to better understand my problem...
public class OriginalClass
{
IPersistence _persistence;
public OriginalClass(IPersistence persistence)
{
this._persistence = persistence;
}
public void DoSomething()
{
// I have all the information needed to send an email / save to disk. But how do I supply it?
this._persistence.Put("Message to save");
}
}
public interface IPersistence
{
bool Put<T>(T data);
}
public class EmailPersistence : IPersistence
{
public bool Put<T>(T data)
{
// How am I going to get the FROM and TO details?
return EmailManager.Send("FROM", "TO", data.ToString());
};
}
public class DiskPersistence : IPersistence
{
public bool Put<T>(T data)
{
// How am I going to get the SAVE PATH details?
// I just used a new initialization. So I'm probably doing this wrong as well...
new System.IO.StreamWriter("SAVE PATH").Write(data.ToString());
return true;
}
}
What you need to do is pass 'just enough' contextual information about the message to the persistence class. Passing on email-specific information like from and to however, causes you to leak implementation details of the persistence mechanism into OriginalClass, which is not something you should want. Doing this will cause you to have to change the OriginalClass everytime you add a new IPersistence implementation. This is obviously bad (it breaks both OCP and DIP).
So what exactly to supply is something only you can determine, but it could be something identifier that allows an implementation to retrieve the required information to operate. This could be something like the ID of the Contactperson or organization for who the message is written. This way you only have to pass in the message and this ID and the implementation can use this ID to query the database to get whatever it needs.
However, if these values do not change during the application's runtime, the solution is completely different. In that case you should simply use constructor injection:
public class EmailPersistence : IPersistence {
private readonly MailAddress from;
private readonly MailAddress to;
public EmailPersistence(MailAddress from, MailAddress to) {
this.from = from;
this.to = to;
}
public bool Put(string data) {
// How am I going to get the FROM and TO details?
return EmailManager.Send(this.from, this.to, data.ToString());
};
}
Since the settings do not change, you can load them from the config file (or from anywhere) during application startup and can simply create a new EmailPersistence using these fixed configuration values.
Something like this should work, As now IEmailManager can also go via the DI framework, all you need to do is to bootstrap the EmailManager Construction.
public class OriginalClass
{
IPersistence _persistence;
public OriginalClass(IPersistence persistence)
{
this._persistence = persistence;
}
public void DoSomething()
{
// I have all the information needed to send an email / save to disk. But how do I supply it?
this._persistence.Put("Message to save");
}
}
public interface IPersistence
{
bool Put<T>(T data);
}
public class EmailPersistence : IPersistence
{
private readonly IEmailManager _manager;
public EmailPersistence(IEmailManager manager)
{
_manager = manager;
}
public bool Put<T>(T data)
{
// How am I going to get the FROM and TO details?
return _manager.Send();
}
}
public class EmailManager : IEmailManager
{
public string From { get; set; }
public string To { get; set; }
public bool Send()
{
throw new NotImplementedException();
}
public dynamic Data { get; set; }
}
public interface IEmailManager
{
string From { get; set; }
string To { get; set; }
dynamic Data { get; set; }
bool Send();
}
public class DiskPersistence : IPersistence
{
public string Path { get; set; }
public DiskPersistence(string path)
{
Path = path;
}
public bool Put<T>(T data)
{
// How am I going to get the SAVE PATH details?
// I just used a new initialization. So I'm probably doing this wrong as well...
new System.IO.StreamWriter(Path).Write(data.ToString());
return true;
}
}
Related
I'm new to Unity and am trying to write some Unity logic which initialises and register/resolves a singleton instance of the Email object so that it can be used across several other objects, one example below being OperationEntity.
So when it's registered it populates the Email singleton with some values from a config file, then whenever an instance of OperationEntity is created (in my case it's being deserialized) it uses that same Email singleton. So all my client logic needs to do is deserialize OperationEntity and call PerformAction() - with the email instance taken care of by Unity.
public interface IEmail
{
string FromName { get; set; }
string FromEmailAddress { get; set; }
}
public class Email : IEmail
{
public string FromName { get; set; }
public string FromEmailAddress { get; set; }
public Email(string fromName, string fromEmailAddress)
{
FromName = fromName;
FromEmailAddress = fromEmailAddress;
}
}
public class OperationEntity
{
private readonly IEmail _email;
public int OperationId { get; set; }
public string OperationName { get; set; }
public string ToAddress { get; set; }
public OperationEntity(IEmail email)
{
_email = email;
}
public void PerformAction()
{
_email.ToAddress = ToAddress;
_email.Body = "Some email body";
_email.Deliver();
}
}
Any help would be appreciated in getting this Unity code to work
public static void Register(IUnityContainer container)
{
container
.RegisterType<IEmail, Email>(
new InjectionFactory(c => new Email(
"To Name",
"to#email.com")));
var email = container.Resolve<IEmail>();
container.RegisterType<OperationEntity>(
"email", new ContainerControlledLifetimeManager(),
new InjectionConstructor(email));
}
First, you need a proper lifetime manager the ContainerControlledLifetimeManager is for singletons.
For custom initialization, you could probably use InjectionFactory
This lets you write any code which initializes the entity.
Edit1: this should help
public static void Register(IUnityContainer container)
{
container
.RegisterType<IEmail, Email>(
new ContainerControlledLifetimeManager(),
new InjectionFactory(c => new Email(
"To Name",
"to#email.com")));
}
and then
var opEntity = container.Resolve<OperationEntity>();
Edit2: To support serialization, you'd have to rebuild dependencies after you deserialize:
public class OperationEntity
{
// make it public and mark as dependency
[Dependency]
public IEmail _email { get; set;}
}
and then
OperationEntity entity = somehowdeserializeit;
// let unity rebuild your dependencies
container.BuildUp( entity );
You could use:
container.RegisterType<IEmail, Email>(new ContainerControlledLifetimeManager());
If IEmail is a singleton with no dependencies (just custom arguments), you can new it up yourself:
container.RegisterInstance<IEmail>(new Email("To Name", "to#email.com"));
That will register the supplied instance as a singleton for the container.
Then you just resolve the service:
container.Resolve<OperationEntity>();
And because you are resolving a concrete type, there is no registration required. Nevertheless, if you would like that service to also be a singleton, you can register it using ContainerControlledLifetimeManager and then all calls to resolve (or when injecting it as a dependency to another class) will return the same instance:
container.RegisterType<OperationEntity>(new ContainerControlledLifetimeManager());
You can, for example, use this code:
public class example : MonoBehaviour
{
public static example instance;
public void Start()
{
(!instance)
instance = this;
}
}
You could implement your own singleton class and extend any class form it.
public class MyClass : MonoBehaviour {
private static MyClass _instance;
public static MyClass Instance { get { return _instance; } }
private void Awake()
{
if (_instance != null && _instance != this)
{
Destroy(this.gameObject);
} else {
_instance = this;
}
}
}
In my .NET 4.0 application I'm accessing application properties through the interface ISettings I prepared:
public interface ISettings
{
int Quota { get; }
string Property2 { get; }
// ...
int PropertyN { get; }
}
// code generated by Visual Studio
public sealed partial class Settings :
global::System.Configuration.ApplicationSettingsBase
{
// application properties generated from app.config
[global::System.Configuration.ApplicationScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("123")]
public int Quota {
get {
return ((int)(this["Quota"]));
}
}
// and so on...
}
// my code to apply the interface to the Settings class
public sealed partial class Settings : ISettings
{
}
In some scenarios I would like to override the values from the config file depending on the organization I'm processing the data for, in example I would like to increase the quota for some organization. Of course, I could create the method similar to:
public int GetQuotaByOrgId(int orgId);
and implement the logic there, but I would like to avoid passing the orgId among the code. The better solution for me would be to create a proxy class overriding only the values I want to change, something like:
public class OverridenSettings : ISettings
{
private ISettings instance;
private int orgId;
private int[] orgsWithBiggerQuota = {1, 2, 132, 6542};
public OverridenSettings(ISettings instance, int orgId)
{
this.instance = instance;
this.orgId = orgId;
}
public override int Quota
{
get
{
int quota = this.instance.Quota;
if (this.orgsWithBiggerQuota.Contains(this.orgId))
{
quota += 1000;
}
return quota;
}
}
// all other properties should be taken from the default instance
}
Is there an elegant way to generate such class without having to explicitely implement all the interface's members just to redirect them to the default instance?
You can use any of the frameworks out there to create a dynamic proxy of your Settings class.
For example using Unity I can create an object of a class(in your case Settings class) like this
ISettings settings = (ISettings)Intercept.NewInstance(typeof(Settings), new VirtualMethodInterceptor(), new IInterceptionBehavior[] { new OrganizationInterceptor(orgId)});
The OrganizationInterceptor has the ability to 'intercept' method calls(including property getters/setters) and could have an implementation like:
public class OrganizationInterceptor : IInterceptionBehavior
{
private int OrgId { get; set; }
private List<int> orgsWithBiggerQuota;
public OrganizationInterceptor(int orgId)
{
OrgId = orgId;
WillExecute = orgId > 0;
}
public IEnumerable<Type> GetRequiredInterfaces()
{
return Type.EmptyTypes;
}
public IMethodReturn Invoke(IMethodInvocation input, GetNextInterceptionBehaviorDelegate getNext)
{
var ret = getNext()(input, getNext);
if (input.MethodBase.IsSpecialName && input.MethodBase.Name == "get_Quota" &&
this.orgsWithBiggerQuota.Contains(OrgId))
ret.ReturnValue = (int)ret.ReturnValue + 100;
return ret;
}
public bool WillExecute { get; set; }
}
I haven't ran this myself so you might need to debug it a bit(especially the Invoke method).
If you want to use the VirtualMethodInterceptor you need to declare your property virtual. There is also TransparentProxyInterceptor which doesnt require this but will create another object that will call into your object(2 objects in total vs 1 in the virtual case).
I have a AddCustomer() that has four parameters (firName, lastName, email, companyId), like below.
public class CustomerService
{
public bool AddCustomer(
string firName, string lastName,
string email, int companyId)
{
//logic: create company object based on companId
//other logic including validation
var customer = //create customer based on argument and company object
//save the customer
}
}
public class Customer
{
public int Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public Company Company { get; set; }
public string EmailAddress { get; set; }
//Other five primitive properties
}
public class Company
{
public int Id { get; set; }
public string Name { get; set; }
}
My Question is that should the AddCustomer's parameter be changed to Customer object, like below, considering SOLID principle. Please note that only four fields shown above are used in the method.
public bool AddCustomer(Customer customer){
}
Update
If below is used:
public bool AddCustomer(Customer customer)
The issue: One of the parameter is CompanyId. Thus, creating a Customer constructor with a CompanyId as parameter might not work on all circumstances. However, without constructor, it would be confusing for AdCustomer()'s client as to what properties to assign.
Update 2
Ideally, i would like to protect invariant of entities Customer and Company by restricting property setters.
An answer very much depends on what the purpose and the responsibility of the CustomerService class and the Customer class is, and what they are intended to achieve.
From your question it would seem ("other logic including validation") that it is the responsibility of CustomerService to determine what constitutes a valid new Customer to be registered, whereas the Customer class itself is nothing more than a DTO without any behavior.
So consider the following hypothetical use cases: a customer's email changes; the Company the Customer works for changes; if the Company is bankrupt, the new Customer registration should be refused; if the Company produces a lot of sales for us, the Customer should be regarded as a Premium Customer. How would such cases be handled and what responsibilities are involved?
You might want to approach this differently, in the sense that you make both intent and behavior explicit, instead of having "AddCustomer", "UpdateCustomer", "DeleteCustomer" and "GetCustomer(Id)". The Customer service could be responsible for service coordination and infrastructure aspects, while the Customer class really focuses on the required domain behavior and customer related business rules.
I will outline one (a CQRS type approach) of several possible approaches to better break up responsibilities, to illustrate this:
Encode behavioral intent and decisions as Commands and Events respectively.
namespace CustomerDomain.Commands
{
public class RegisterNewCustomer : ICommand
{
public RegisterNewCustomer(Guid registrationId, string firstName, string lastName, string email, int worksForCompanyId)
{
this.RegistrationId = registrationId;
this.FirstName = firstName;
// ... more fields
}
public readonly Guid RegistrationId;
public readonly string FirstName;
// ... more fields
}
public class ChangeCustomerEmail : ICommand
{
public ChangeCustomerEmail(int customerId, string newEmail)
// ...
}
public class ChangeCustomerCompany : ICommand
{
public ChangeCustomerCompany(int customerId, int newCompanyId)
// ...
}
// ... more commands
}
namespace CustomerDomain.Events
{
public class NewCustomerWasRegistered : IEvent
{
public NewCustomerWasRegistered(Guid registrationId, int assignedId, bool isPremiumCustomer, string firstName /* ... other fields */)
{
this.RegistrationId = registrationId;
// ...
}
public readonly Guid RegistrationId;
public readonly int AssignedCustomerId;
public readonly bool IsPremiumCustomer;
public readonly string FirstName;
// ...
}
public class CustomerRegistrationWasRefused : IEvent
{
public CustomerRegistrationWasRefused(Guid registrationId, string reason)
// ...
}
public class CustomerEmailWasChanged : IEvent
public class CustomerCompanyWasChanged : IEvent
public class CustomerWasAwardedPremiumStatus : IEvent
public class CustomerPremiumStatusWasRevoked : IEvent
}
This allows expressing intent very clearly, and including only the information that is actually needed to accomplish a specific task.
Use small and dedicated services to deal with the needs of your application domain in making decisions:
namespace CompanyIntelligenceServices
{
public interface ICompanyIntelligenceService
{
CompanyIntelligenceReport GetIntelligenceReport(int companyId);
// ... other relevant methods.
}
public class CompanyIntelligenceReport
{
public readonly string CompanyName;
public readonly double AccumulatedSales;
public readonly double LastQuarterSales;
public readonly bool IsBankrupt;
// etc.
}
}
Have the CustomerService implementation deal with infrastructure / coordination concerns:
public class CustomerDomainService : IDomainService
{
private readonly Func<int> _customerIdGenerator;
private readonly Dictionary<Type, Func<ICommand, IEnumerable<IEvent>>> _commandHandlers;
private readonly Dictionary<int, List<IEvent>> _dataBase;
private readonly IEventChannel _eventsChannel;
private readonly ICompanyIntelligenceService _companyIntelligenceService;
public CustomerDomainService(ICompanyIntelligenceService companyIntelligenceService, IEventChannel eventsChannel)
{
// mock database.
var id = 1;
_customerIdGenerator = () => id++;
_dataBase = new Dictionary<int, List<IEvent>>();
// external services and infrastructure.
_companyIntelligenceService = companyIntelligenceService;
_eventsChannel = eventsChannel;
// command handler wiring.
_commandHandlers = new Dictionary<Type,Func<ICommand,IEnumerable<IEvent>>>();
SetHandlerFor<RegisterNewCustomerCommand>(cmd => HandleCommandFor(-1,
(id, cust) => cust.Register(id, cmd, ReportFor(cmd.WorksForCompanyId))));
SetHandlerFor<ChangeCustomerEmail>(cmd => HandleCommandFor(cmd.CustomerId,
(id, cust) => cust.ChangeEmail(cmd.NewEmail)));
SetHandlerFor<ChangeCustomerCompany>(cmd => HandleCommandFor(cmd.CustomerId,
(id, cust) => cust.ChangeCompany(cmd.NewCompanyId, ReportFor(cmd.NewCompanyId))));
}
public void PerformCommand(ICommand cmd)
{
var commandHandler = _commandHandlers[cmd.GetType()];
var resultingEvents = commandHandler(cmd);
foreach (var evt in resultingEvents)
_eventsChannel.Publish(evt);
}
private IEnumerable<IEvent> HandleCommandFor(int customerId, Func<int, Customer, IEnumerable<IEvent>> handler)
{
if (customerId <= 0)
customerId = _customerIdGenerator();
var events = handler(LoadCustomer(customerId));
SaveCustomer(customerId, events);
return events;
}
private void SetHandlerFor<TCommand>(Func<TCommand, IEnumerable<IEvent>> handler)
{
_commandHandlers[typeof(TCommand)] = cmd => handler((TCommand)cmd);
}
private CompanyIntelligenceReport ReportFor(int companyId)
{
return _companyIntelligenceService.GetIntelligenceReport(companyId);
}
private Customer LoadCustomer(int customerId)
{
var currentHistoricalEvents = new List<IEvent>();
_dataBase.TryGetValue(customerId, out currentHistoricalEvents);
return new Customer(currentHistoricalEvents);
}
private void SaveCustomer(int customerId, IEnumerable<IEvent> newEvents)
{
List<IEvent> currentEventHistory;
if (!_dataBase.TryGetValue(customerId, out currentEventHistory))
_dataBase[customerId] = currentEventHistory = new List<IEvent>();
currentEventHistory.AddRange(newEvents);
}
}
And then that allows you to really focus on the required behavior, business rules and decisions for the Customer class, maintaining only the state needed to perform decisions.
internal class Customer
{
private int _id;
private bool _isRegistered;
private bool _isPremium;
private bool _canOrderProducts;
public Customer(IEnumerable<IEvent> eventHistory)
{
foreach (var evt in eventHistory)
ApplyEvent(evt);
}
public IEnumerable<IEvent> Register(int id, RegisterNewCustomerCommand cmd, CompanyIntelligenceReport report)
{
if (report.IsBankrupt)
yield return ApplyEvent(new CustomerRegistrationWasRefused(cmd.RegistrationId, "Customer's company is bankrupt"));
var isPremium = IsPremiumCompany(report);
yield return ApplyEvent(new NewCustomerWasRegistered(cmd.RegistrationId, id, isPremium, cmd.FirstName, cmd.LastName, cmd.Email, cmd.WorksForCompanyID));
}
public IEnumerable<IEvent> ChangeEmail(string newEmailAddress)
{
EnsureIsRegistered("change email");
yield return ApplyEvent(new CustomerEmailWasChanged(_id, newEmailAddress));
}
public IEnumerable<IEvent> ChangeCompany(int newCompanyId, CompanyIntelligenceReport report)
{
EnsureIsRegistered("change company");
var isPremiumCompany = IsPremiumCompany(report);
if (!_isPremium && isPremiumCompany)
yield return ApplyEvent(new CustomerWasAwardedPremiumStatus(_id));
else
{
if (_isPremium && !isPremiumCompany)
yield return ApplyEvent(new CustomerPremiumStatusRevoked(_id, "Customer changed workplace to a non-premium company"));
if (report.IsBankrupt)
yield return ApplyEvent(new CustomerLostBuyingCapability(_id, "Customer changed workplace to a bankrupt company"));
}
}
// ... handlers for other commands
private bool IsPremiumCompany(CompanyIntelligenceReport report)
{
return !report.IsBankrupt &&
(report.AccumulatedSales > 1000000 || report.LastQuarterSales > 10000);
}
private void EnsureIsRegistered(string forAction)
{
if (_isRegistered)
throw new DomainException(string.Format("Cannot {0} for an unregistered customer", forAction));
}
private IEvent ApplyEvent(IEvent evt)
{
// build up only the status needed to take domain/business decisions.
// instead of if/then/else, event hander wiring could be used.
if (evt is NewCustomerWasRegistered)
{
_isPremium = evt.IsPremiumCustomer;
_isRegistered = true;
_canOrderProducts = true;
}
else if (evt is CustomerRegistrationWasRefused)
_isRegistered = false;
else if (evt is CustomerWasAwardedPremiumStatus)
_isPremium = true;
else if (evt is CustomerPremiumStatusRevoked)
_isPremium = false;
else if (evt is CustomerLostBuyingCapability)
_canOrderProducts = false;
return evt;
}
}
An added benefit is that the Customer class in this case is completely isolated from any infrastructure concerns can be easily tested for correct behavior and the customer domain module can be easily changed or extended to accommodate new requirements without breaking existing clients.
yes.... if its valid to create a customer with those 4 properties.... ideally you'd have a constructor with those 4. that way the create responsibility lives with the customer object and Customer Service doesn't need to know about it, it just deals with "Customers".
How about using the builder pattern resulting in code somewhat like this:
var customer = new CustomerBuilder()
.firstName("John")
.lastName("Doe")
.email("john.doe#example.com")
.companyId(6)
.createCustomer();
customerService.AddCustomer(customer);
Then you can have your builder class handle looking up company objects when createCustomer is called and the order of parameters no longer matters and you have a convenient place to put logic to choose sensible defaults.
This also gives you a convenient location for validation logic so you can't get an invalid instance of Customer in the first place.
Or another possible way would be to have AddCustomer return a command object so your client code could do this:
customerService.AddCustomer()
.firstName("John")
.lastName("Doe")
.email("john.doe#example.com")
.companyId(6)
.execute();
I am working with insurance and have two different policy types - motor and household, represented by two different classes, Motor and Household.
Both have several bits of data in common, so both would inherit from another class called Policy. When a user logs into the app, they could have either a motor or a household policy, so the app needs to display the generic information and the information unique to Motor or Household. To encapsulate all this, i have a response object that has both a Motor member and a Household member, as shown below:
public class Response
{
...
private MotorPolicy _motorPolicy;
private HouseholdPolicy _householdPolicy;
....
}
The code below should demonstrate:
if (response.PolicyType == Enumerations.PolicyType.Motor)
{
lblDescription.Text = response.MotorPolicy.Description;
lblReg.Text = response.MotorPolicy.Reg;
}
else
{
lblDescription.Text = response.HouseholdPolicy.Description;
lblContents.Text = response.HouseholdPolicy.Contents;
}
The MotorPolicy doesn't have Contents property and the HouseholdPolicy doesn't have a Reg property.
But I really want to simply do:
if (response.PolicyType == Enumerations.PolicyType.Motor)
{
lblDescription.Text = response.Policy.Description;
...
}
I have tried using generics, could couldn't find the right solution.
Your response only needs a Policy type, you can then store a MotorPolicy or HouseholdPolicy type into it.
Then your response just needs to check for data type
if (response.Policy is MotorPolicy) ....
Alternatively have an abstract method or a property returning data from an abstract method on the Policy type that is fully inplemented by the child classes and returns reg data or contents data as apporpriate.
Each Policy descendant (now you have two, you might have more in the future, right?) should have their own UI controls which "know" how to deal with the policy information. The same approach can be used for other things, such as a "controller" for policy objects etc.
The response can then be made generic:
public class Response<T> where T: Policy {
...
private T _policy;
....
}
Alternatively, you could have a more generic approach which uses reflection to display the information, but those are usually less "sexy" in their appearance and usability (think of the Property Grid in the VS designer).
public interface IPolicy
{
string Description { get; }
string Reg { get; }
string Contents { get; }
}
public class MotorPolicy : IPolicy
{
public string Description
{
get { return ...; }
}
public string Reg
{
get { return ...; }
}
public string Contents
{
get { return String.Empty; }
}
}
public class HousholdPolicy : IPolicy
{
public string Description
{
get { return ...; }
}
public string Reg
{
get { return String.Empty; }
}
public string Contents
{
get { return ...; }
}
}
public class Response
{
...
private IPolicy _policy;
....
}
Now you don't need an Enumeration to show which type you've implemented, you can just say
lblDescription.Text = response.Policy.Description;
lblReg.Text = response.Policy.Reg;
lblContents.Text = response.Policy.Contents;
Edit: Alternate solution
public interface IPolicy
{
string Description { get; }
}
public interface IHasReg
{
string Reg { get; }
}
public interface IHasContents
{
string Contents { get; }
}
public class MotorPolicy : IPolicy, IHasReg
{
public string Description
{
get { return ...; }
}
public string Reg
{
get { return ...; }
}
}
public class HouseholdPolicy : IPolicy, IHasContents
{
public string Description
{
get { return ...; }
}
public string Contents
{
get { return ...; }
}
}
public class Response
{
...
private IPolicy _policy;
....
}
This leaves you with more code in the calling function
lblDescription.Text = response.Policy.Description;
IHasReg hasReg = response.Policy as IHasReg;
if (hasReg != null) lblReg.Text = hasReg.Reg;
IHasContents hasContents = response.Policy as IHasContents;
if (hasContents != null) lblContents.Text = hasContents.Contents;
but is considerably more extensible than other options presented and complies with your desire to avoid functionality in the implementation which doesn't make sense.
One option is to add a member to Policy that synthesizes all the derived class' relevant properties to provide a summary:
public abstract class Policy {
public string Description { get; set; }
public abstract string Summary { get; }
}
public class MotorPolicy: Policy {
public override string Summary {
get { return this.Description + "\r\n" + this.Reg; }
}
}
public class HouseholdPolicy: Policy {
public override string Summary {
get { return this.Description + "\r\n" + this.Contents; }
}
}
This centralizes the logic and makes the user interface code simple:
label.Description.Text = response.Policy.Summary;
That basic implementation sacrifices the ability to format the subsections separately. You could overcome that by exposing the summary as a collection of strings:
public abstract IEnumerable<string> SummarySections { get; }
If you want to display the derived classes' details in fundamentally different ways, you'll have to embrace the conditional logic in the user interface layer (for example, you might list the household policy's contents in a table, but show a scanned image for the motor policy's registration).
Use the template pattern:
Create a base class called Policy with a virtual abstract get method to determine the description of the policy.
public abstract class Policy
{
protected virtual string GetDescription()
{
return string.Empty()
}
public string Description
{
get
{
return GetDescription();
}
}
}
public MotorPolicy : Policy
{
public override string GetDescription()
{
return ..... ////specific description implementation for MotorPolicy
}
}
public HouseHoldPolicy : Policy
{
public override string GetDescription()
{
return ..... ////specific description implementation for HouseholdPolicy
}
}
public class Response
{
...
private MotorPolicy _motorPolicy;
private HouseholdPolicy _householdPolicy;
private PolicyType _policyType;
....
public Policy Policy
{
get
{
if (_policyType== PolicyType.Motor)
{
return _motorPolicy;
}
if (_policyType== PolicyType.Household)
{
return _householdPolicy;
}
return null;
}
}
}
client code:
if (response.Policy != null)
{
lblDescription.Text = response.Policy.Description;
...
}
Let MotorPolicy and HouseholdPolicy derive from Policy and override the abstract get method from the base and create a specific implementation of it.
In the Response class just get the description.
The simplest solution would be to implement an interface with a description property and a "contents" property, and then in your motor policy class, create a dummy "contents" property which returns "reg".
Can your response contain either a MotorPolicy or a HouseholdPolicy or, can it contain one of each?
If you are dealing with one or the other then create a base type that both classes inherit that defines the common properties. When you output the common properties just cast the Policy as the base type and use that.
My immediate thought is to go for:
public abstract class Response
{
public abstract Policy Policy {get;}//can be used for stuff for dealing with all policies.
public static Response GetResponse(Policy policy)
{//factory method
if(policy is MotorPolicy)
return new MotorResponse((MotorPolicy)policy);
if(policy is HouseholdPolicy)
return new HouseholdResponse((HouseholdPolicy)policy);
throw new ArgumentException("Unexpected policy type");
}
}
public class MotorResponse : Response
{
private readonly MotorPolicy _motorPolicy;
public MotorResponse(MotorPolicy policy)
{
_motorPolicy = policy;
}
protected override Policy Policy
{
get { return _motorPolicy; }
}
// motor specific stuff
}
public class HouseholdResponse : Response
{
private readonly HouseholdPolicy _householdPolicy;
public HouseholdResponse(HouseholdPolicy policy)
{
_householdPolicy = policy;
}
protected override Policy Policy
{
get { return _householdPolicy; }
}
// household specific stuff
}
I would try something like this:
public class Response
{
public Policy SelectedPolicy {get;set;}
//I don't think you need these, but hard to
//say without seeing the rest of the code
...
private MotorPolicy _motorPolicy;
private HouseholdPolicy _householdPolicy;
....
}
then
lblDescription.Text = response.SelectedPolicy.Description;
if (SelectedPolicy is MotorPolicy)
lblReg.Text = ((MotorPolicy)response.SelectedPolicy).Reg;
else if (SelectedPolicy is HouseholdPolicy)
lblContents.Text = ((HouseholdPolicy)response.SelectedPolicy).Contents;
I would not put both Reg and Contents in the base class or interface. If I do what's the purpose of inheritance if all classes look the same? The only benefits I would get would be types, and that's not going to gain me much in this case.
maybe I don't understand the question but I would just use inheritence
define policy as
public class Policy
{
public string Description{ get; set;}
public string Details {get; set;}
}
public class MotorPolicy:Policy
{
public void SetReg(string reg)
{
base.Details = reg;
}
}
public class HousePolicy:Policy
{
public void SetContents(string contents)
{
base.Details = contents;
}
}
and call by
private void Form1_Load(object sender, EventArgs e)
{
MotorPolicy mp = new MotorPolicy();
mp.Description = "Motor";
SetForm(mp);
}
private void SetForm(Policy p)
{
lblDescription.Text = p.Description;
lblDetail.Text = p.Details;
//then if you still need specifics
if (p.GetType() == typeof(MotorPolicy))
{
MotorPolicy mp = p as MotorPolicy;
//continue assigning mp
}
else if (p.GetType() == typeof(HousePolicy))
{
HousePolicy hp = p as HousePolicy;
//continue assigning Hp
}
}
Note I put reg/contents as a field detail as they are both string types. If one was int vs string then they would have to be done separate.
define the Policy interface and implement it in your both the policy classes
Interface IPolicy{
int Reg {get;set;};
string Contents {get;set;};
}
MotorPolicy : Policy,IPolicy {
string IPolicy.Contents
{get;set;};
int IPolicy.Reg
{get;set;};
}
HouseholdPolicy : Policy , IPolicy {
string IPolicy.Contents
{get;set;};
int IPolicy.Reg
{get;set;};
}
Yours is a unique example of "Refactoring condition to Polymorphism" [Fowler].
And then your method should accept the proper object and do as below:
public void Update(IPolicy policy)
{
lblDescription.Text = policy.Description;
lblReg.Text = .Reg;
}
Well, I dislike abstract classes so I went with an interface for Policy
public interface IPolicy
{
string Description { get; set;}
void Display();
}
Then we inherit from it to create MotorPolicy
public class MotorPolicy : IPolicy
{
public string Description { get; set; }
public string Reg { get; set; }
public void Display()
{
Console.WriteLine(string.Format("Description: {0}", Description));
Console.WriteLine(string.Format("Reg: {0}", Reg));
}
}
Then for response I changed the Policy to a List in the off chance that you can have both or either. Now we've offloaded the handling of displaying the data to the specific policy itself.
public class Response
{
public List<IPolicy> Policies { get; set; }
public void Display()
{
Policies.ForEach(p => p.Display());
}
public void Display(Type t)
{
var policy = (from p in Policies
where p.GetType() == t
select p).FirstOrDefault();
policy.Display();
}
}
This could easily be changed to not use the List and we can get rid of the overloaded Display.
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?