Related
I'm having trouble writing up some code. I'm not too sure where and how to write up the constructors and the accessors.
The activity I have to do is this:
Write 3 derived classes to allow a user to enter the details of three types of Vehicles with their attributes.
• Car (make, model, year, bodyType)
• Airplane (make, model, year, noEngines, engineType)
• Boat (make, model, year, length, hullType)
The 4th class is the base class Vehicle which contains the shared attributes and methods
Make all attributes either private (in derived classes) or protected (in base class) and write accessor methods for each attribute.
Write 2 constructors for each derived class. One with no arguments and the other which accepts the values of the attributes in the derived class as arguments.
Write a Console Application called Fleet.cs which creates and displays 2 of each Vehicle type
My code so far is as follows:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ConsoleApplication5
{
class Vehicle
{
static void Main(string[] args)
{
}
class Car
{
protected string make
{
get
{
return make;
}
set
{
make = value;
}
}
protected string model
{
get
{
return model;
}
set
{
model = value;
}
}
protected int year
{
get
{
return year;
}
set
{
year = value;
}
}
protected string bodyType
{
get
{
return bodyType;
}
set
{
bodyType = value;
}
}
public bool isInitialized;
public Car()
{
isInitialized = true;
}
}
}
class Airplane
{
protected string make
{
get
{
return make;
}
set
{
make = value;
}
}
protected string model
{
get
{
return model;
}
set
{
model = value;
}
}
protected int year
{
get
{
return year;
}
set
{
year = value;
}
}
protected int numEngines
{
get
{
return numEngines;
}
set
{
numEngines = value;
}
}
protected int engineType
{
get
{
return engineType;
}
set
{
engineType = value;
}
}
}
class Boat
{
protected string make
{
get
{
return make;
}
set
{
make = value;
}
}
protected string model
{
get
{
return model;
}
set
{
model = value;
}
}
protected string year
{
get
{
return year;
}
set
{
year = value;
}
}
protected string length
{
get
{
return length;
}
set
{
length = value;
}
}
protected string hullType
{
get
{
return hullType;
}
set
{
hullType = value;
}
}
}
}
First part the OOP principles
Classes:
A class is a construct that enables you to create your own custom
types by grouping together variables of other types, methods and
events. A class is like a blueprint. It defines the data and behavior
of a type. If the class is not declared as static, client code can use
it by creating objects or instances which are assigned to a variable.
The variable remains in memory until all references to it go out of
scope. At that time, the CLR marks it as eligible for garbage
collection. If the class is declared as static, then only one copy
exists in memory and client code can only access it through the class
itself, not an instance variable. For more information, see Static
Classes and Static Class Members (C# Programming Guide). Unlike
structs, classes support inheritance, a fundamental characteristic of
object-oriented programming. For more information, see Inheritance (C#
Programming Guide).
Also objects are instances of classes.
Inheritance:
Inheritance, together with encapsulation and polymorphism, is one of
the three primary characteristics (or pillars) of object-oriented
programming. Inheritance enables you to create new classes that reuse,
extend, and modify the behavior that is defined in other classes. The
class whose members are inherited is called the base class, and the
class that inherits those members is called the derived class. A
derived class can have only one direct base class. However,
inheritance is transitive. If ClassC is derived from ClassB, and
ClassB is derived from ClassA, ClassC inherits the members declared in
ClassB and ClassA.
Derived class:
A class that was created based on a previously existing class (i.e., base class). A derived class inherits all of the member variables and methods of the base class from which it is derived.
Also called a derived type.
Method:
A method (or message) in object-oriented programming (OOP) is a
procedure associated with an object class. An object is made up of
behavior and data. Data is represented as properties of the object and
behavior as methods. Methods are also the interface an object presents
to the outside world. For example a window object would have methods
such as open and close. One of the most important capabilities that a
method provides is method overriding. The same name (e.g., area) can
be used for multiple different kinds of classes. This allows the
sending objects to invoke behaviors and to delegate the implementation
of those behaviors to the receiving object. For example an object can
send an area message to another object and the appropriate formula
will be invoked whether the receiving object is a rectangle,circle,
triangle, etc.
Attributes and properties:
"Fields", "class variables", and "attributes" are more-or-less the
same - a low-level storage slot attached to an object. Each language's
documentation might use a different term consistently, but most actual
programmers use them interchangeably. (However, this also means some
of the terms can be ambiguous, like "class variable" - which can be
interpreted as "a variable of an instance of a given class", or "a
variable of the class object itself" in a language where class objects
are something you can manipulate directly.)
"Properties" are, in most languages I use, something else entirely -
they're a way to attach custom behaviour to reading / writing a field.
(Or to replace it.)
So if you want to categorize them they are OOP(Object Oriented Programming) principles.
Second part:
Write a Console Application called Fleet.cs which creates and displays
2 of each Vehicle type.
So one way of doing this is creating vehicles as hardcoded. The other way is to ask user for vehicle details with Console.Readline(). Main method could look something like this.
static void Main(string[] args)
{
Vehicle v1 = new Vehicle { Make = "test1", Model = "model1", Year = 1996 };
Vehicle v2 = new Vehicle { Make = "test2", Model = "model2", Year = 1997 };
Console.WriteLine(v1);
Console.WriteLine(v2);
...
}
And then you would override the ToString() method for each class. Like this:
public override string ToString()
{
return string.Format("Vehicle is {0} and of model {1} and is made in {2}.", make, model, year);
}
Here you also can use base.ToString() to get the data of upper (base) class in the derivided class.
EDIT 1: User input:
So if you want the user input you could make program like this:
static void Main(string[] args)
{
//input
Vehicle v1 = new Vehicle();
Console.Write("Enter the make of 1st vehicle: ");
v1.Make = Console.ReadLine();
Console.Write("Enter the model of 1st vehicle: ");
v1.Model = Console.ReadLine();
Console.WriteLine("Enter the year of manufacturing for 1st vehicle:");
v1.Year = int.Parse(Console.ReadLine());
//output
Console.WriteLine("The data for 1st vehicle: ");
Console.WriteLine(v1);
...
}
Even better would be to create Input method in the class and calling it from Main program. So code would not be repeating itself.
Finished program
Vehicle.cs
using System;
class Vehicle
{
string make, model;
int year;
public string Make { get { return make; } set { make = value; } }
public string Model { get { return model; } set { model = value; } }
public int Year { get { return year; } set { year = value; } }
public Vehicle()
{
make = model = "Unknown";
year = 0;
}
public Vehicle(string make, string model, int year)
{
this.make = make;
this.model = model;
this.year = year;
}
public virtual void GetFromInput()
{
Console.Write("Enter the make of vehicle: ");
Make = Console.ReadLine();
Console.Write("Enter the model of vehicle: ");
Model = Console.ReadLine();
Console.WriteLine("Enter the year of manufacturing for vehicle: ");
Year = int.Parse(Console.ReadLine());
}
public override string ToString()
{
return string.Format("Vehicle is {0} and of model {1} and is made in {2}.", make, model, year);
}
}
Car.cs
using System;
class Car : Vehicle
{
string bodyType;
public string BodyType { get { return bodyType; } set { bodyType = value; } }
public Car() : base()
{
bodyType = "Unknown";
}
public Car(string make, string model, int year, string bodyType) : base(make, model, year)
{
this.bodyType = bodyType;
}
public override void GetFromInput()
{
base.GetFromInput();
Console.Write("Enter body type for the car: ");
BodyType = Console.ReadLine();
}
public override string ToString()
{
return base.ToString() + string.Format("This vehicle is a car with body type of {0}.", BodyType);
}
}
Airplane.cs
using System;
class Airplane : Vehicle
{
int noEngines;
string engineType;
public int NumberOfEngines{ get { return noEngines; } set { noEngines = value; } }
public string EngineType { get { return engineType; } set { engineType = value; } }
public Airplane() : base()
{
noEngines = 0;
engineType = "Unknown";
}
public Airplane(string make, string model, int year, int noEngines, string engineType) : base(make, model, year)
{
this.noEngines = noEngines;
this.engineType = engineType;
}
public override void GetFromInput()
{
base.GetFromInput();
Console.Write("Enter the number of engines on an airplane: ");
NumberOfEngines = int.Parse(Console.ReadLine());
Console.Write("Enter the engine type for the airplane: ");
EngineType = Console.ReadLine();
}
public override string ToString()
{
return base.ToString() + string.Format("This vehicle is an airplane with {0} engines and engine type of {1}.", NumberOfEngines, EngineType);
}
}
Boat.cs
using System;
class Boat : Vehicle
{
int length;
string hullType;
public int Length { get { return length; } set { length = value; } }
public string HullType { get { return hullType; } set { hullType = value; } }
public Boat() : base()
{
length = 0;
hullType = "Unknown";
}
public Boat(string make, string model, int year, int length, string hullType) : base(make, model, year)
{
this.length = length;
this.hullType = hullType;
}
public override void GetFromInput()
{
base.GetFromInput();
Console.Write("Enter the length of the boat: ");
Length = int.Parse(Console.ReadLine());
Console.Write("Enter the hull type for the boat: ");
HullType = Console.ReadLine();
}
public override string ToString()
{
return base.ToString() + string.Format("This vehicle is a boat with length of {0} and hull type of {1}.", Length, HullType);
}
}
Fleet.cs
using System;
class Fleet
{
static void Main(string[] args)
{
Vehicle v1 = new Vehicle();
v1.GetFromInput();
Console.WriteLine(v1);
//... for the other vehicles
}
}
This can be achieved using class inheritance.
Each of your vehicle classes, need to inherit a common class that implements functionality need by 'all' vehicles, This class (Vehicle receptively), can then be used in C# to identify any type of vehicle class/type.
Instead of having a several classes where each class is solely responsible for a type of vechile, you can abstract out common functionality needed by each vehicle, and implement a class that exposes these common relationships:
using System;
public namespace CodeSpace {
public class Vehicle {
public Vehicle(Type type, string make, string model) {
Model = model;
Make = make;
Type = type;
}
public Type VehicleType { get; private set; }
public string Make { get; set; }
public string Model { get; set; }
}
public class Airplane : Vehicle {
public class Airplane(string make, string model) : base(typeof(Airplane), make, model) {
}
}
public class Boat : Vehicle {
public class Boat(string make, string model) : base(typeof(Boat), make, model) {
}
}
public class Car : Vehicle {
public class Car(string make, string model) : base(typeof(Car), make, model) {
}
}
class Program {
public static void Main(params string[] args ) {
var vehicles = new List<Vehicle>() {
new Boat("Canoe", "X2") as Vehicle,
new Boat("Raft", "A") as Vehicle,
new Car("Ford", "T") as Vehicle,
new Airplane("BMW", "Idk") as Vehicle,
};
foreach(var v in vehicles) {
Console.WriteLine(v.VehicleType.FullName);
}
}
}
}
Now all of your vehicles can be identified using one class that exposes all vehicles through a common interface.
This might be a simple/basic OOP question, but I still cannot figure out how to solve it.
I had the following problem during an interview : make an UML class diagram and write the basic code for a "smart"phone which contains the functionalities of a telephone and of an mp3 player. We've got with the following (accepted) solution :
class Telephone
{
public string name { get; set; }
public Telephone()
{
name = "name telephone";
}
}
class MP3
{
public string name { get; set; }
public MP3()
{
name = "name mp3";
}
}
And the "smart"phone class :
class TelephoneMP3
{
public Telephone tel;
public MP3 mp3;
public TelephoneMP3()
{
tel = new Telephone();
mp3 = new MP3();
}
}
As you can see, we have a composition relation between the TelephoneMP3 and the Telephone/MP3 classes.
But, using this code, the TelephoneMP3 is not a Telephone and the TelephoneMP3 is not an MP3 either, which is not logical. So, what changes should I make in order to make this valid ? For example, this kind of test :
if (telMp3 is Telephone)
{
Console.WriteLine("TelephoneMP3 is telephone");
}
if (telMp3 is MP3)
{
Console.WriteLine("TelephoneMP3 is mp3");
}
The modifications could be made using the following remarks :
Telephone / MP3 / TelephoneMP3 must remain classes (all 3 of them)
I could add interfaces / other classes if necessary
TelephoneMP3 must not duplicate all the functionalities from a Telephone / MP3 (for example during an inheritance from an interface where the TelephoneMP3 will be obliged to write the code from all the interface's members)
Thank you in advance
Since C# doesn't support multiple inheritance, consider using interfaces instead:
public interface Phone{ ... }
public interface Mp3{ ... }
public class Telephone : Phone{ ... }
public class Mp3Player : Mp3{ ... }
public class Smartphone : Phone, Mp3{ ... }
This way Smartphone is both Phone and Mp3. If you are in need to write a method which operates on a Telephone, use the Phone interface instead. This way you'll be able to pass either Telephone or Smartphone as an argument.
There are some good answers here. The answers which say to use interfaces are good, and that's what the interviewer is likely looking for. However, I would consider simply denying the premise that the "is-a-kind-of" relationship being satisified is a good idea. Rather, I would consider using a service provider organization:
public interface ITelephone { ... }
internal class MyTelephone : ITelephone { ... }
public interface IMusicPlayer { ... }
internal class MyPlayer : IMusicPlayer { ... }
public interface IServiceProvider
{
T QueryService<T>() where T : class;
}
internal class MyDevice : IServiceProvider
{
MyTelephone phone = new MyTelephone();
MyPlayer player = new MyPlayer();
public T QueryService<T>() where T : class
{
if (typeof(T) == typeof(ITelephone)) return (T)(object)phone;
if (typeof(T) == typeof(IPlayer)) return (T)(object)player;
return null;
}
}
Now a caller has a MyDevice in hand via its IServiceProvider interface. You ask it
ITelephone phone = myDevice.QueryService<ITelephone>();
and if phone is non-null, then the device can act like a phone. But
myDevice is ITelephone
is false. The device is not a phone, it knows how to find you something that acts like a phone.
For more in this vein, study plug-in architectures such as MAF.
It is almost similar to the other answers, but..
I think it has the best accuracy regarding the inheritance hierarchy.
internal class Program
{
private static void Main(string[] args)
{
var telephone = new Telephone();
Console.WriteLine(telephone.Name);
telephone.OutboundCall("+1 234 567");
Console.WriteLine("Am I a Telephone? {0}", telephone is Telephone);
Console.WriteLine("Am I a MP3? {0}", telephone is MediaPlayer3);
Console.WriteLine("Am I a Smartphone? {0}", telephone is Smartphone);
Console.WriteLine("Do I Have Telephone Capabilities? {0}", telephone is ITelephone);
Console.WriteLine("Do I Have MP3 Capabilities? {0}", telephone is IMediaPlayer3);
Console.WriteLine();
var mp3 = new MediaPlayer3();
Console.WriteLine(mp3.Name);
mp3.PlaySong("Lalala");
Console.WriteLine("Am I a Telephone? {0}", mp3 is Telephone);
Console.WriteLine("Am I a MP3? {0}", mp3 is MediaPlayer3);
Console.WriteLine("Am I a Smartphone? {0}", mp3 is Smartphone);
Console.WriteLine("Do I Have Telephone Capabilities? {0}", mp3 is ITelephone);
Console.WriteLine("Do I Have MP3 Capabilities? {0}", mp3 is IMediaPlayer3);
Console.WriteLine();
var smartphone = new Smartphone();
Console.WriteLine(smartphone.Name);
smartphone.OutboundCall("+1 234 567");
smartphone.PlaySong("Lalala");
Console.WriteLine("Am I a Telephone? {0}", smartphone is Telephone);
Console.WriteLine("Am I a MP3? {0}", smartphone is MediaPlayer3);
Console.WriteLine("Am I a Smartphone? {0}", smartphone is Smartphone);
Console.WriteLine("Do I Have Telephone Capabilities? {0}", smartphone is ITelephone);
Console.WriteLine("Do I Have MP3 Capabilities? {0}", smartphone is IMediaPlayer3);
Console.ReadKey();
}
public interface IDevice
{
string Name { get; }
}
public interface ITelephone : IDevice
{
void OutboundCall(string number);
}
public interface IMediaPlayer3 : IDevice
{
void PlaySong(string filename);
}
public class Telephone : ITelephone
{
public string Name { get { return "Telephone"; } }
public void OutboundCall(string number)
{
Console.WriteLine("Calling {0}", number);
}
}
public class MediaPlayer3 : IMediaPlayer3
{
public string Name { get { return "MP3"; } }
public void PlaySong(string filename)
{
Console.WriteLine("Playing Song {0}", filename);
}
}
public class Smartphone : ITelephone, IMediaPlayer3
{
private readonly Telephone telephone;
private readonly MediaPlayer3 mp3;
public Smartphone()
{
telephone = new Telephone();
mp3 = new MediaPlayer3();
}
public string Name { get { return "Smartphone"; } }
public void OutboundCall(string number)
{
telephone.OutboundCall(number);
}
public void PlaySong(string filename)
{
mp3.PlaySong(filename);
}
}
}
Program Output:
Telephone
Calling +1 234 567
Am I a Telephone? True
Am I a MP3? False
AM I a Smartphone? False
Do I Have Telephone Capabilities? True
Do I Have MP3 Capabilities? False
MP3
Playing Song Lalala
Am I a Telephone? False
Am I a MP3? True
AM I a Smartphone? False
Do I Have Telephone Capabilities? False
Do I Have MP3 Capabilities? True
Smartphone
Calling +1 234 567
Playing Song Lalala
Am I a Telephone? False
Am I a MP3? False
AM I a Smartphone? True
Do I Have Telephone Capabilities? True
Do I Have MP3 Capabilities? True
I think this interview question is not (as should be all interview questions) about the challenge itself. The coding exercise of merging two classes via composition could be answered with a textbook. This challenge is a subtle trick question, and I propose that the point is to get you to discuss why. At least that's what I would want from my interviewees.
This test:
if(telMp3 is Telephone && telMp3 is MP3) {
...is the real problem. Why must you meet this criteria? This test completely voids the purpose of building objects out of composition. It demands that the objects are implemented in a specific way. It shows that the existing class implementations are already tightly coupled to the codebase (if they cannot be done away with). These requirements mean that SOLID principles were not followed, because you can't just fulfill the methods of a base type, you have to actually be the base type. That's no good.
As other answers have said, the solution would be to use interfaces. Then you can pass your object to any method that requires the interface. This kind of usage would require a test like so:
if (telMp3 is IPhone && telMp3 is IMp3) {
...but you can't do that, because of the limitation of your challenge. That means that out there in the rest of your code, people have been writing methods that explicitly depend on the specific types Telephone and MP3. That is the real problem.
In my opinion, the correct answer to this challenge is to say that the codebase fails the test. The specific fallout in your challenge is irrelvant; you need to change the requirements of the challenge before you can solve it properly. An interviewee would who recognize this fact would pass the test with flying colors.
You can use explicit interface implemenations as well to limit usage of the shared variable Name. That way you would have to cast to the interface to access it. You can still have public properties / methods from the interface.
Composition is still used, but the SmartPhone has control over the implementations of their properties / methods.
To me, this would be the easiest implementation to work with, because I rarely want to use both the implementation from the mp3player and the phone, but rather one of them. Also, I still have full control over what happens when the interfaces methods are called on the SmartPhone.
class User
{
void UseSmartPhone(SmartPhone smartPhone)
{
// Cannot access private property 'Name' here
Console.WriteLine(smartPhone.Name);
// Cannot access explicit implementation of 'IMp3Player.Play'
smartPhone.Play();
// You can send the phone to the method that accepts an IMp3Player though
PlaySong(smartPhone);
// This works fine. You are sure to get the Phone name here.
Console.WriteLine(((IPhone)smartPhone).Name);
// This works fine, since the Call is public in SmartPhone.
smartPhone.Call();
}
void CallSomeone(IPhone phone)
{
phone.Call();
}
void PlaySong(IMp3Player player)
{
player.Play();
}
}
class SmartPhone : IPhone, IMp3Player
{
private Phone mPhone;
private Mp3Player mMp3Player;
public SmartPhone()
{
mPhone = new Phone();
mMp3Player = new Mp3Player();
}
public void Call()
{
mPhone.Call();
}
string IPhone.Name
{
get { return mPhone.Name; }
}
string IMp3Player.Name
{
get { return mMp3Player.Name; }
}
void IMp3Player.Play()
{
mMp3Player.Play();
}
}
class Mp3Player
{
public string Name { get; set; }
public void Play()
{
}
}
class Phone
{
public string Name { get; set; }
public void Call()
{
}
}
interface IPhone
{
string Name { get; }
void Call();
}
interface IMp3Player
{
string Name { get; }
void Play();
}
How about this solution:
public interface ITelephone
{
string Name{get;}
void MakeCall();
}
public interface IMp3
{
string Name { get; }
void Play(string filename);
}
public abstract class BaseTelephone : ITelephone
{
public virtual string Name { get { return "Telephone"; } }
void MakeCall()
{
// code to make a call.
}
}
public class MyMp3Player : IMp3
{
public string Name { get { return "Mp3 Player"; } }
public void Play(string filename)
{
// code to play an mp3 file.
}
}
public class SmartPhone : BaseTelephone, IMp3
{
public override string Name { get { return "SmartPhone"; } }
private IMp3 Player { get { return _Player; } set { _Player = value; } }
private IMp3 _Player = new MyMp3Player();
public void Play(string filename) { Player.Play(filename); }
}
This way the smart phone can also be an Mp3 player, but internally it has an Mp3 player that it uses to play the music. The internal player can be swapped for a new one (eg. upgrade) by using the SmartPhone Player property.
The code for the phone is only written once, in the base phone class. The code for the Mp3 player is only written once also - in the MyMp3Player class.
Use the strategy pattern (used some shortcuts below, you'll get the gist).
public class Device {
private List<App> apps;
public Device() {
this.apps = new List<App>();
this.apps.Add(new Mp3Player());
this.apps.Add(new Telephone());
}
}
public class Mp3Player implements App {...}
public class Telephone implements App {...}
public interface App {...}
Disclaimer: my native tongue is PHP, forgive me any non C# coding standards etc etc.
You could use implicit casting
class TelephoneMP3
{
public Telephone tel;
public MP3 mp3;
public TelephoneMP3()
{
tel = new Telephone();
mp3 = new MP3();
}
public static implicit operator Telephone(TelephoneMP3 telemp3) {
return telemp3.tel;
}
public static implicit operator MP3(TelephoneMP3 telemp3) {
return telemp3.mp3;
}
}
It won't pass the exact test that you proposed, but you can do
var teleMp3 = new TelephoneMP3();
Telephone t = teleMp3;
You are trying to model a product hierarchy, in which a given product may have its own specific properties, as well as being composed of standard sub-products. This is indeed an example of the composition pattern. I suggest introducing a base interface for any product component, then creating specific interfaces for telephone, MP3 player and smartphone products.
In the traditional composition pattern each node may contain an arbitrary list of components to which subcomponents can be added or removed, however in your data model it appears more useful for each specific type of product to specify its precise children, then provide a generic method to iterate over them. This allows for specific (sub)components of a specified type/interface to be easily queryable throughout the product hierarchy.
I've also introduced an interface for a GPS product since all new phones contain built-in GPS receivers -- just to illustrate how to work with recursive hierarchies of components.
public interface IProductComponent
{
string Name { get; set; }
IEnumerable<IProductComponent> ChildComponents { get; }
IEnumerable<IProductComponent> WalkAllComponents { get; }
TProductComponent UniqueProductComponent<TProductComponent>() where TProductComponent : class, IProductComponent;
}
public interface ITelephone : IProductComponent
{
IGps Gps { get; }
}
public interface IMp3Player : IProductComponent
{
}
public interface IGps : IProductComponent
{
double AltitudeAccuracy { get; }
}
public interface ISmartPhone : IProductComponent
{
ITelephone Telephone { get; }
IMp3Player Mp3Player { get; }
}
These interfaces could then be implemented by a parallel set of classes:
public abstract class ProductComponentBase : IProductComponent
{
string name;
protected ProductComponentBase(string name)
{
this.name = name;
}
#region IProductComponent Members
public string Name
{
get
{
return name;
}
set
{
name = value;
}
}
public virtual IEnumerable<IProductComponent> ChildComponents
{
get
{
return Enumerable.Empty<IProductComponent>();
}
}
public IEnumerable<IProductComponent> WalkAllComponents
{
get
{
yield return this;
foreach (var child in ChildComponents)
{
foreach (var subChild in child.WalkAllComponents)
yield return subChild;
}
}
}
public TProductComponent UniqueProductComponent<TProductComponent>() where TProductComponent : class, IProductComponent
{
TProductComponent foundComponent = null;
foreach (var child in WalkAllComponents.OfType<TProductComponent>())
{
if (foundComponent == null)
foundComponent = child;
else
throw new Exception("Duplicate products found of type " + typeof(TProductComponent).Name);
}
return foundComponent;
}
#endregion
}
public class Telephone : ProductComponentBase, ITelephone
{
IGps gps = new Gps();
public Telephone()
: base("telephone")
{
}
#region ITelephone Members
public IGps Gps
{
get
{
return gps;
}
}
#endregion
IEnumerable<IProductComponent> BaseChildComponents
{
get
{
return base.ChildComponents;
}
}
public override IEnumerable<IProductComponent> ChildComponents
{
get
{
if (Gps != null)
yield return Gps;
foreach (var child in BaseChildComponents)
yield return child;
}
}
}
public class Gps : ProductComponentBase, IGps
{
public Gps()
: base("gps")
{
}
#region IGps Members
public double AltitudeAccuracy
{
get { return 100.0; }
}
#endregion
}
public class TelephoneMP3 : ProductComponentBase, ISmartPhone
{
ITelephone telephone;
IMp3Player mp3Player;
public TelephoneMP3()
: base("TelephoneMP3")
{
this.telephone = new Telephone();
this.mp3Player = new MP3();
}
IEnumerable<IProductComponent> BaseChildComponents
{
get
{
return base.ChildComponents;
}
}
public override IEnumerable<IProductComponent> ChildComponents
{
get
{
if (Telephone != null)
yield return Telephone;
if (Mp3Player != null)
yield return Mp3Player;
foreach (var child in BaseChildComponents)
yield return child;
}
}
#region ISmartPhone Members
public ITelephone Telephone
{
get { return telephone; }
}
public IMp3Player Mp3Player
{
get { return mp3Player; }
}
#endregion
}
public class MP3 : ProductComponentBase, IMp3Player
{
public MP3()
: base("mp3Player")
{
}
}
As new product component types are added (or subclassed), they override the "ChildComponents" of their parent and return their domain specific children.
Having done this, you can (recursively) query the product hierarchy for components of a given type for your use. For instance:
var accuracy = smartPhone.UniqueProductComponent<IGps>().AltitudeAccuracy
or
bool hasPhone = (component.UniqueProductComponent<ITelephone>() != null)
This combination of generalization and composition avoids duplicating code while making explicit the type of sub-components that should be found in any given product. It also avoids the burden of making all higher-level products proxy the interfaces of their standard children, passing all calls on to them.
Contrary to all the other answers I am quite confident the way this question is asked makes it impossible. The reason is the following :
You explicitly state
But, using this code, the TelephoneMP3 is not a Telephone and the TelephoneMP3 is not an MP3 either, which is not logical. So, what changes should I make in order to make this valid ?
Seeing the word "is" makes me immediately think of the "is" operator. I immediately assume that this is what you really want.
You then go on later to say the following:
Telephone / MP3 / TelephoneMP3 must remain classes (all 3 of them)
Well sure we can do the following:
interface ITelephone { }
class Telephone
{
public string name { get; set; }
public Telephone()
{
name = "name telephone";
}
}
interface IMP3 { }
class MP3 : IMP3
{
public string name { get; set; }
public MP3()
{
name = "name mp3";
}
}
class TelephoneMP3 : ITelephone, IMP3
{
public Telephone tel;
public MP3 mp3;
public TelephoneMP3()
{
tel = new Telephone();
mp3 = new MP3();
}
}
But we still have one problem. The word "is". Since we must keep the classes TelephoneMP3, Telephone and MP3 and C# does not support multiply inheritance it simply is not possible.
To Illustrate my point:
public class Program
{
static void Main(string[] args)
{
TelephoneMP3 t = new TelephoneMP3();
Console.WriteLine((t is TelephoneMP3)? true:false);
Console.WriteLine((t is ITelephone) ? true : false);
Console.WriteLine((t is IMP3) ? true : false);
Console.WriteLine((t is Telephone) ? true : false);
Console.WriteLine((t is MP3) ? true : false);
Console.ReadLine();
}
}
This will give you
True
True
True
False
False
In other words TelephoneMP3 "is" an ITelephone. TelephoneMP3 "is" an IMP3; however, it is not possible for a TelephoneMP3 to be both a MP3 and a Telephone.
C# does not support multiple inheritance, you need to use interfaces and abstract class for common implementations , You can do the follwing :
Edit : I have add more details to my answer
abstract class BaseDevice
{
public string name { get; set; }
public void Print()
{
Console.WriteLine("{0}", name );
}
}
public interface IPhone
{
void DoPhone();
}
public interface IMP3
{
void DoMP3();
}
class Telephone :BaseDevice , IPhone
{
public Telephone()
{
name = "name telephone";
}
}
class MP3 : BaseDevice , IMP3
{
public MP3()
{
name = "name mp3";
}
}
class telMp3 : BaseDevice , IMP3, IPhone
{
private Telephone _tel;
private MP3 _mp3;
public telMp3()
{
name = "name telMp3";
}
public void DoPhone()
{
_tel.DoPhone();
}
public void DoMP3()
{
_mp3.DoMP3();
}
}
My application consist of server and client, which are independant. They communicate through objects created and modified by server. Client is provided with read-only interfaces of this objects. As far as I know, that's the correct way to keep encapsulation in OOP. See example:
// Client-side
interface IBox<T> where T : ITool
{
IEnumerable<T> Tools { get; }
}
interface ITool
{
void Use();
}
// Server-side
class Box : IBox<Tool>
{
public List<Tool> ToolList = new List<Tool>();
public IEnumerable<ITool> Tools
{
get { return ToolList; }
}
}
class Tool : ITool
{
string _msg = "default msg";
public string Msg
{
get { return _msg; }
set { _msg = value; }
}
public void Use()
{
Console.WriteLine("Tool used! Msg: {0}", _msg);
}
}
As you see, I have to use generics, because my objects form a hierarchy.
That looked nice, until I've decided to add a Room class with interface IRoom, which have to generalize not only IBox, but ITool too:
interface IRoom<B, T>
where B : IBox<T>
where T : ITool
{
IEnumerable<B> Boxes { get; }
}
class Room : IRoom<Box, Tool>
{
public List<Box> BoxList = new List<Box>();
public IEnumerable<Box> Boxes
{
get { return BoxList; }
}
}
Now, imagine that we have a Room consist of not only boxes. I need at least 3 collections of absolutely different things there, which are collections of several types too. So, there must be a huge tree, and my root class become something like: Room : IRoom<Box, Tool1, Tool2, Tool3, Wardrobe, Coat, Jeans, Hat, Table, Computer, Book, Pen>
I'm not sure, that is right. So, I'm asking, what is true OOP-way of implementing my task? (with no reflection, breaking encapsulation, type casting or other bad tricks)
Starting with the .NET Framework 4 and C# 4 you can use IEnumerable's covariance and just avoid using generics.
// Client-side
interface IBox
{
IEnumerable<ITool> Tools { get; }
}
interface ITool
{
void Use();
}
// Server-side
class Box : IBox
{
public List<Tool> ToolList = new List<Tool>();
public IEnumerable<ITool> Tools
{
get { return ToolList; } // With .NET 3.5 and earlier cast here is neccessary to compile
// Cast to interfaces shouldn't be so much of a performance penalty, I believe.
}
}
class Tool : ITool
{
string _msg = "default msg";
public string Msg
{
get { return _msg; }
set { _msg = value; }
}
public void Use()
{
Console.WriteLine("Tool used! Msg: {0}", _msg);
}
}
interface IRoom
{
IEnumerable<IBox> Boxes { get; }
}
class Room : IRoom
{
public List<Box> BoxList = new List<Box>();
public IEnumerable<IBox> Boxes
{
get { return BoxList; } // and here...
}
}
Covariance and contravariance in generics described here: http://msdn.microsoft.com/en-us/library/dd799517.aspx
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?
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"; }
}
}