Use Of Factory Method/Abstract Factory Pattern
I have the following simplified requirement of parsing an inventory file that contains the letter of the brand of car and the corresponding spec string on each line. For example:
A Sedan
B Blue
And below I provide a simplified version of the code:
class StockManager
List<ICar> cars = new List<ICar>();
public StockManager(List<string> inventoryFileLines)
foreach(var inventoryFileLine in inventoryFileLines)
string parts = inventoryFileLine.Split(' ');
cars.Add(CreateCar(parts[0], parts[1]));
public decimal CalculateTotal()
decimal total = 0;
foreach(var car in cars)
total += car.GetPrice();
return total;
public ICar CreateCar(string brand, string spec)
if(brand == "A")
return new CarA(spec);
else if(brand == "B")
return new CarB(spec);
throw new Exception();
interface ICar
decimal GetPrice();
class CarA : ICar
string type;
public CarA(string type)
this.type = type;
public decimal GetPrice()
if(type == "Sedan")
return 30000;
else if (type == "SUV")
return 50000;
throw new Exception();
class CarB : ICar
string color;
public CarB(string color)
this.color = color;
public decimal GetPrice()
if (color == "Orange")
return 20000;
else if (color == "Red")
return 25000;
throw new Exception();
In the future, new brands and specs might be added. This is the change that I should anticipate and provide flexibility for.
Now I want to apply the right design patterns but apply them for the right reasons, not just for the sake of having applied a design pattern. (As stated by GoF: “A design pattern should only be applied when the flexibility it affords is actually needed.”)
The first thing that came to my mind is the factory method or abstract factory pattern. So when there is a new car brand C is added in the future:
Factory Method
Make CreateCar virtual and override it in the new StockManager class that I will be using:
class StockManager2 : StockManager
public StockManager2(List<string> inventoryFileLines) : base(inventoryFileLines)
public override ICar CreateCar(string brand, string spec)
if (brand == "C")
...
return base.CreateCar(brand, spec);
Abstract Factory
Make CreateCar method into its own abstract factory class and provide it to the StockManager class.
Both these refactorings look great if I want to use different alternative creation options at run-time, such as multiple valid CreateCar
factories. And the Maze example is given by GoF also expands on this idea.
But as a matter of fact, the change I anticipate is not an alternative factory but a modified factory. So it seems much more logical to me to modify the CreateCar
method instead of creating a new factory class and leaving the old one obsolete (speaking for the Abstract Factory method here). And the same holds true for creating a second StockManager2 class in the case of Factory method.
I know that Open/Closed principle (O of SOLID by Robert Martin) says not to modify the class but extend it, and the factory pattern does exactly that but does the above example justify its use, given the extensibility requirement I mentioned in the beginning? It seems like the requirement is not an extension in the sense explained in GoF but a true modification instead. But I would like to be corrected if I am wrong.
java c# design-patterns
|
show 1 more comment
I have the following simplified requirement of parsing an inventory file that contains the letter of the brand of car and the corresponding spec string on each line. For example:
A Sedan
B Blue
And below I provide a simplified version of the code:
class StockManager
List<ICar> cars = new List<ICar>();
public StockManager(List<string> inventoryFileLines)
foreach(var inventoryFileLine in inventoryFileLines)
string parts = inventoryFileLine.Split(' ');
cars.Add(CreateCar(parts[0], parts[1]));
public decimal CalculateTotal()
decimal total = 0;
foreach(var car in cars)
total += car.GetPrice();
return total;
public ICar CreateCar(string brand, string spec)
if(brand == "A")
return new CarA(spec);
else if(brand == "B")
return new CarB(spec);
throw new Exception();
interface ICar
decimal GetPrice();
class CarA : ICar
string type;
public CarA(string type)
this.type = type;
public decimal GetPrice()
if(type == "Sedan")
return 30000;
else if (type == "SUV")
return 50000;
throw new Exception();
class CarB : ICar
string color;
public CarB(string color)
this.color = color;
public decimal GetPrice()
if (color == "Orange")
return 20000;
else if (color == "Red")
return 25000;
throw new Exception();
In the future, new brands and specs might be added. This is the change that I should anticipate and provide flexibility for.
Now I want to apply the right design patterns but apply them for the right reasons, not just for the sake of having applied a design pattern. (As stated by GoF: “A design pattern should only be applied when the flexibility it affords is actually needed.”)
The first thing that came to my mind is the factory method or abstract factory pattern. So when there is a new car brand C is added in the future:
Factory Method
Make CreateCar virtual and override it in the new StockManager class that I will be using:
class StockManager2 : StockManager
public StockManager2(List<string> inventoryFileLines) : base(inventoryFileLines)
public override ICar CreateCar(string brand, string spec)
if (brand == "C")
...
return base.CreateCar(brand, spec);
Abstract Factory
Make CreateCar method into its own abstract factory class and provide it to the StockManager class.
Both these refactorings look great if I want to use different alternative creation options at run-time, such as multiple valid CreateCar
factories. And the Maze example is given by GoF also expands on this idea.
But as a matter of fact, the change I anticipate is not an alternative factory but a modified factory. So it seems much more logical to me to modify the CreateCar
method instead of creating a new factory class and leaving the old one obsolete (speaking for the Abstract Factory method here). And the same holds true for creating a second StockManager2 class in the case of Factory method.
I know that Open/Closed principle (O of SOLID by Robert Martin) says not to modify the class but extend it, and the factory pattern does exactly that but does the above example justify its use, given the extensibility requirement I mentioned in the beginning? It seems like the requirement is not an extension in the sense explained in GoF but a true modification instead. But I would like to be corrected if I am wrong.
java c# design-patterns
You fill the inventoryFileLines somewhere else. Why don't you create your cars there and fill the StockManager with the List<Car> instead of List<String>? The only reason to change for the StockManager would be some other responsiblities on managing the stock.
– Charlie
Nov 12 '18 at 20:35
@thomas I don't see how moving this logic to another place would change the case.
– John L.
Nov 12 '18 at 20:38
That is the essence of structural patterns :-) You can create a factory for loading the file and create some cars. The only reason to change for the factory would be a diffrent file format or new cars.
– Charlie
Nov 12 '18 at 20:41
You can avoid creating new car classes if you use a decorator.
– Charlie
Nov 12 '18 at 20:43
1
I think the use of the term "factory" is creating some confusion. What you're describing is more like a class that reads a string and returns a car. And you want to hide all of those implementation details from the class that needs the car. One way to start is by describing what the class that needs the car wants to do, and write an interface for it.public interface ICarReader ICar Read(string value);
Write the interface from the perspective of the class that needs it. Then you can figure out what you want your implementation to be.
– Scott Hannen
Nov 12 '18 at 20:50
|
show 1 more comment
I have the following simplified requirement of parsing an inventory file that contains the letter of the brand of car and the corresponding spec string on each line. For example:
A Sedan
B Blue
And below I provide a simplified version of the code:
class StockManager
List<ICar> cars = new List<ICar>();
public StockManager(List<string> inventoryFileLines)
foreach(var inventoryFileLine in inventoryFileLines)
string parts = inventoryFileLine.Split(' ');
cars.Add(CreateCar(parts[0], parts[1]));
public decimal CalculateTotal()
decimal total = 0;
foreach(var car in cars)
total += car.GetPrice();
return total;
public ICar CreateCar(string brand, string spec)
if(brand == "A")
return new CarA(spec);
else if(brand == "B")
return new CarB(spec);
throw new Exception();
interface ICar
decimal GetPrice();
class CarA : ICar
string type;
public CarA(string type)
this.type = type;
public decimal GetPrice()
if(type == "Sedan")
return 30000;
else if (type == "SUV")
return 50000;
throw new Exception();
class CarB : ICar
string color;
public CarB(string color)
this.color = color;
public decimal GetPrice()
if (color == "Orange")
return 20000;
else if (color == "Red")
return 25000;
throw new Exception();
In the future, new brands and specs might be added. This is the change that I should anticipate and provide flexibility for.
Now I want to apply the right design patterns but apply them for the right reasons, not just for the sake of having applied a design pattern. (As stated by GoF: “A design pattern should only be applied when the flexibility it affords is actually needed.”)
The first thing that came to my mind is the factory method or abstract factory pattern. So when there is a new car brand C is added in the future:
Factory Method
Make CreateCar virtual and override it in the new StockManager class that I will be using:
class StockManager2 : StockManager
public StockManager2(List<string> inventoryFileLines) : base(inventoryFileLines)
public override ICar CreateCar(string brand, string spec)
if (brand == "C")
...
return base.CreateCar(brand, spec);
Abstract Factory
Make CreateCar method into its own abstract factory class and provide it to the StockManager class.
Both these refactorings look great if I want to use different alternative creation options at run-time, such as multiple valid CreateCar
factories. And the Maze example is given by GoF also expands on this idea.
But as a matter of fact, the change I anticipate is not an alternative factory but a modified factory. So it seems much more logical to me to modify the CreateCar
method instead of creating a new factory class and leaving the old one obsolete (speaking for the Abstract Factory method here). And the same holds true for creating a second StockManager2 class in the case of Factory method.
I know that Open/Closed principle (O of SOLID by Robert Martin) says not to modify the class but extend it, and the factory pattern does exactly that but does the above example justify its use, given the extensibility requirement I mentioned in the beginning? It seems like the requirement is not an extension in the sense explained in GoF but a true modification instead. But I would like to be corrected if I am wrong.
java c# design-patterns
I have the following simplified requirement of parsing an inventory file that contains the letter of the brand of car and the corresponding spec string on each line. For example:
A Sedan
B Blue
And below I provide a simplified version of the code:
class StockManager
List<ICar> cars = new List<ICar>();
public StockManager(List<string> inventoryFileLines)
foreach(var inventoryFileLine in inventoryFileLines)
string parts = inventoryFileLine.Split(' ');
cars.Add(CreateCar(parts[0], parts[1]));
public decimal CalculateTotal()
decimal total = 0;
foreach(var car in cars)
total += car.GetPrice();
return total;
public ICar CreateCar(string brand, string spec)
if(brand == "A")
return new CarA(spec);
else if(brand == "B")
return new CarB(spec);
throw new Exception();
interface ICar
decimal GetPrice();
class CarA : ICar
string type;
public CarA(string type)
this.type = type;
public decimal GetPrice()
if(type == "Sedan")
return 30000;
else if (type == "SUV")
return 50000;
throw new Exception();
class CarB : ICar
string color;
public CarB(string color)
this.color = color;
public decimal GetPrice()
if (color == "Orange")
return 20000;
else if (color == "Red")
return 25000;
throw new Exception();
In the future, new brands and specs might be added. This is the change that I should anticipate and provide flexibility for.
Now I want to apply the right design patterns but apply them for the right reasons, not just for the sake of having applied a design pattern. (As stated by GoF: “A design pattern should only be applied when the flexibility it affords is actually needed.”)
The first thing that came to my mind is the factory method or abstract factory pattern. So when there is a new car brand C is added in the future:
Factory Method
Make CreateCar virtual and override it in the new StockManager class that I will be using:
class StockManager2 : StockManager
public StockManager2(List<string> inventoryFileLines) : base(inventoryFileLines)
public override ICar CreateCar(string brand, string spec)
if (brand == "C")
...
return base.CreateCar(brand, spec);
Abstract Factory
Make CreateCar method into its own abstract factory class and provide it to the StockManager class.
Both these refactorings look great if I want to use different alternative creation options at run-time, such as multiple valid CreateCar
factories. And the Maze example is given by GoF also expands on this idea.
But as a matter of fact, the change I anticipate is not an alternative factory but a modified factory. So it seems much more logical to me to modify the CreateCar
method instead of creating a new factory class and leaving the old one obsolete (speaking for the Abstract Factory method here). And the same holds true for creating a second StockManager2 class in the case of Factory method.
I know that Open/Closed principle (O of SOLID by Robert Martin) says not to modify the class but extend it, and the factory pattern does exactly that but does the above example justify its use, given the extensibility requirement I mentioned in the beginning? It seems like the requirement is not an extension in the sense explained in GoF but a true modification instead. But I would like to be corrected if I am wrong.
java c# design-patterns
java c# design-patterns
edited Nov 12 '18 at 21:11
John L.
asked Nov 12 '18 at 20:11
John L.John L.
549921
549921
You fill the inventoryFileLines somewhere else. Why don't you create your cars there and fill the StockManager with the List<Car> instead of List<String>? The only reason to change for the StockManager would be some other responsiblities on managing the stock.
– Charlie
Nov 12 '18 at 20:35
@thomas I don't see how moving this logic to another place would change the case.
– John L.
Nov 12 '18 at 20:38
That is the essence of structural patterns :-) You can create a factory for loading the file and create some cars. The only reason to change for the factory would be a diffrent file format or new cars.
– Charlie
Nov 12 '18 at 20:41
You can avoid creating new car classes if you use a decorator.
– Charlie
Nov 12 '18 at 20:43
1
I think the use of the term "factory" is creating some confusion. What you're describing is more like a class that reads a string and returns a car. And you want to hide all of those implementation details from the class that needs the car. One way to start is by describing what the class that needs the car wants to do, and write an interface for it.public interface ICarReader ICar Read(string value);
Write the interface from the perspective of the class that needs it. Then you can figure out what you want your implementation to be.
– Scott Hannen
Nov 12 '18 at 20:50
|
show 1 more comment
You fill the inventoryFileLines somewhere else. Why don't you create your cars there and fill the StockManager with the List<Car> instead of List<String>? The only reason to change for the StockManager would be some other responsiblities on managing the stock.
– Charlie
Nov 12 '18 at 20:35
@thomas I don't see how moving this logic to another place would change the case.
– John L.
Nov 12 '18 at 20:38
That is the essence of structural patterns :-) You can create a factory for loading the file and create some cars. The only reason to change for the factory would be a diffrent file format or new cars.
– Charlie
Nov 12 '18 at 20:41
You can avoid creating new car classes if you use a decorator.
– Charlie
Nov 12 '18 at 20:43
1
I think the use of the term "factory" is creating some confusion. What you're describing is more like a class that reads a string and returns a car. And you want to hide all of those implementation details from the class that needs the car. One way to start is by describing what the class that needs the car wants to do, and write an interface for it.public interface ICarReader ICar Read(string value);
Write the interface from the perspective of the class that needs it. Then you can figure out what you want your implementation to be.
– Scott Hannen
Nov 12 '18 at 20:50
You fill the inventoryFileLines somewhere else. Why don't you create your cars there and fill the StockManager with the List<Car> instead of List<String>? The only reason to change for the StockManager would be some other responsiblities on managing the stock.
– Charlie
Nov 12 '18 at 20:35
You fill the inventoryFileLines somewhere else. Why don't you create your cars there and fill the StockManager with the List<Car> instead of List<String>? The only reason to change for the StockManager would be some other responsiblities on managing the stock.
– Charlie
Nov 12 '18 at 20:35
@thomas I don't see how moving this logic to another place would change the case.
– John L.
Nov 12 '18 at 20:38
@thomas I don't see how moving this logic to another place would change the case.
– John L.
Nov 12 '18 at 20:38
That is the essence of structural patterns :-) You can create a factory for loading the file and create some cars. The only reason to change for the factory would be a diffrent file format or new cars.
– Charlie
Nov 12 '18 at 20:41
That is the essence of structural patterns :-) You can create a factory for loading the file and create some cars. The only reason to change for the factory would be a diffrent file format or new cars.
– Charlie
Nov 12 '18 at 20:41
You can avoid creating new car classes if you use a decorator.
– Charlie
Nov 12 '18 at 20:43
You can avoid creating new car classes if you use a decorator.
– Charlie
Nov 12 '18 at 20:43
1
1
I think the use of the term "factory" is creating some confusion. What you're describing is more like a class that reads a string and returns a car. And you want to hide all of those implementation details from the class that needs the car. One way to start is by describing what the class that needs the car wants to do, and write an interface for it.
public interface ICarReader ICar Read(string value);
Write the interface from the perspective of the class that needs it. Then you can figure out what you want your implementation to be.– Scott Hannen
Nov 12 '18 at 20:50
I think the use of the term "factory" is creating some confusion. What you're describing is more like a class that reads a string and returns a car. And you want to hide all of those implementation details from the class that needs the car. One way to start is by describing what the class that needs the car wants to do, and write an interface for it.
public interface ICarReader ICar Read(string value);
Write the interface from the perspective of the class that needs it. Then you can figure out what you want your implementation to be.– Scott Hannen
Nov 12 '18 at 20:50
|
show 1 more comment
1 Answer
1
active
oldest
votes
You can use the runtime object creation mechanism. So the c# will be created the class based on the string. The only expectation the class name and the given string must be the same.
But you can use a static dictionary if the values are not the same.
Here is the code:
public ICar CreateCar(string brand, string spec)
System.Type type = typeof( ICar ).Assembly.GetTypes().Where( t => t.Name == brand ).FirstOrDefault();
object instance = Activator.CreateInstance( type, new object[ 1 ] specs );
return (ICar)instance;
of course this function does not handle any error, but it is the easy part.
By the way, in your code please use the NotImplementedException instead of Exception base class, because this is what you want :) implement the new brands.
add a comment |
Your Answer
StackExchange.ifUsing("editor", function ()
StackExchange.using("externalEditor", function ()
StackExchange.using("snippets", function ()
StackExchange.snippets.init();
);
);
, "code-snippets");
StackExchange.ready(function()
var channelOptions =
tags: "".split(" "),
id: "1"
;
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function()
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled)
StackExchange.using("snippets", function()
createEditor();
);
else
createEditor();
);
function createEditor()
StackExchange.prepareEditor(
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader:
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
,
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
);
);
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53269400%2fuse-of-factory-method-abstract-factory-pattern%23new-answer', 'question_page');
);
Post as a guest
Required, but never shown
1 Answer
1
active
oldest
votes
1 Answer
1
active
oldest
votes
active
oldest
votes
active
oldest
votes
You can use the runtime object creation mechanism. So the c# will be created the class based on the string. The only expectation the class name and the given string must be the same.
But you can use a static dictionary if the values are not the same.
Here is the code:
public ICar CreateCar(string brand, string spec)
System.Type type = typeof( ICar ).Assembly.GetTypes().Where( t => t.Name == brand ).FirstOrDefault();
object instance = Activator.CreateInstance( type, new object[ 1 ] specs );
return (ICar)instance;
of course this function does not handle any error, but it is the easy part.
By the way, in your code please use the NotImplementedException instead of Exception base class, because this is what you want :) implement the new brands.
add a comment |
You can use the runtime object creation mechanism. So the c# will be created the class based on the string. The only expectation the class name and the given string must be the same.
But you can use a static dictionary if the values are not the same.
Here is the code:
public ICar CreateCar(string brand, string spec)
System.Type type = typeof( ICar ).Assembly.GetTypes().Where( t => t.Name == brand ).FirstOrDefault();
object instance = Activator.CreateInstance( type, new object[ 1 ] specs );
return (ICar)instance;
of course this function does not handle any error, but it is the easy part.
By the way, in your code please use the NotImplementedException instead of Exception base class, because this is what you want :) implement the new brands.
add a comment |
You can use the runtime object creation mechanism. So the c# will be created the class based on the string. The only expectation the class name and the given string must be the same.
But you can use a static dictionary if the values are not the same.
Here is the code:
public ICar CreateCar(string brand, string spec)
System.Type type = typeof( ICar ).Assembly.GetTypes().Where( t => t.Name == brand ).FirstOrDefault();
object instance = Activator.CreateInstance( type, new object[ 1 ] specs );
return (ICar)instance;
of course this function does not handle any error, but it is the easy part.
By the way, in your code please use the NotImplementedException instead of Exception base class, because this is what you want :) implement the new brands.
You can use the runtime object creation mechanism. So the c# will be created the class based on the string. The only expectation the class name and the given string must be the same.
But you can use a static dictionary if the values are not the same.
Here is the code:
public ICar CreateCar(string brand, string spec)
System.Type type = typeof( ICar ).Assembly.GetTypes().Where( t => t.Name == brand ).FirstOrDefault();
object instance = Activator.CreateInstance( type, new object[ 1 ] specs );
return (ICar)instance;
of course this function does not handle any error, but it is the easy part.
By the way, in your code please use the NotImplementedException instead of Exception base class, because this is what you want :) implement the new brands.
edited Nov 16 '18 at 20:16
answered Nov 12 '18 at 20:53
György GulyásGyörgy Gulyás
554324
554324
add a comment |
add a comment |
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53269400%2fuse-of-factory-method-abstract-factory-pattern%23new-answer', 'question_page');
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
You fill the inventoryFileLines somewhere else. Why don't you create your cars there and fill the StockManager with the List<Car> instead of List<String>? The only reason to change for the StockManager would be some other responsiblities on managing the stock.
– Charlie
Nov 12 '18 at 20:35
@thomas I don't see how moving this logic to another place would change the case.
– John L.
Nov 12 '18 at 20:38
That is the essence of structural patterns :-) You can create a factory for loading the file and create some cars. The only reason to change for the factory would be a diffrent file format or new cars.
– Charlie
Nov 12 '18 at 20:41
You can avoid creating new car classes if you use a decorator.
– Charlie
Nov 12 '18 at 20:43
1
I think the use of the term "factory" is creating some confusion. What you're describing is more like a class that reads a string and returns a car. And you want to hide all of those implementation details from the class that needs the car. One way to start is by describing what the class that needs the car wants to do, and write an interface for it.
public interface ICarReader ICar Read(string value);
Write the interface from the perspective of the class that needs it. Then you can figure out what you want your implementation to be.– Scott Hannen
Nov 12 '18 at 20:50