Use Of Factory Method/Abstract Factory Pattern










3















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.










share|improve this question
























  • 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
















3















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.










share|improve this question
























  • 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














3












3








3


1






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.










share|improve this question
















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






share|improve this question















share|improve this question













share|improve this question




share|improve this question








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


















  • 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













1 Answer
1






active

oldest

votes


















0














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.






share|improve this answer
























    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
    );



    );













    draft saved

    draft discarded


















    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









    0














    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.






    share|improve this answer





























      0














      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.






      share|improve this answer



























        0












        0








        0







        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.






        share|improve this answer















        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.







        share|improve this answer














        share|improve this answer



        share|improve this answer








        edited Nov 16 '18 at 20:16

























        answered Nov 12 '18 at 20:53









        György GulyásGyörgy Gulyás

        554324




        554324



























            draft saved

            draft discarded
















































            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.




            draft saved


            draft discarded














            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





















































            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







            Popular posts from this blog

            Use pre created SQLite database for Android project in kotlin

            Darth Vader #20

            Ondo