www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Factory pattern for classes

reply lexxn <aleksandar.m.nikolov gmail.com> writes:
I'm trying to get the factory pattern going with classes
class A {}

class B {}

class C {}

auto getClassById(uint id)
{
     if (id == 0) {
         return cast(A)Object.factory("A");
     } else if(id == 1) {
         return cast(B)Object.factory("B");
     } else {
         return cast(C)Object.factory("C");
     }
}

I'm getting 2 errors:
main.d(69): Error: Expected return type of main.A, not main.B:
main.d(67):        Return type of main.Ainferred here.

Also is it possible to completely skip the getClassById function 
and if I've and array string classes = ["A", "B"] to just 
cast(classes[0])Object.factory(classes[0]);. I understand that I 
need to cast classes[0].
Aug 09 2020
parent reply Steven Schveighoffer <schveiguy gmail.com> writes:
On 8/9/20 5:16 AM, lexxn wrote:
 I'm trying to get the factory pattern going with classes
 class A {}
 
 class B {}
 
 class C {}
 
 auto getClassById(uint id)
 {
      if (id == 0) {
          return cast(A)Object.factory("A");
      } else if(id == 1) {
          return cast(B)Object.factory("B");
      } else {
          return cast(C)Object.factory("C");
      }
 }
 
 I'm getting 2 errors:
 main.d(69): Error: Expected return type of main.A, not main.B:
 main.d(67):        Return type of main.Ainferred here.
Change your return type to Object.
 Also is it possible to completely skip the getClassById function and if 
 I've and array string classes = ["A", "B"] to just 
 cast(classes[0])Object.factory(classes[0]);. I understand that I need to 
 cast classes[0].
This won't work. If you know what your class is going to be, I'd just import the file that contains it and avoid the whole Object.factory deal. It's going to go away anyways. In other words: Object getClassById(uint id) { if (id == 0) { return new A; } else if(id == 1) { return new B; } else { return new C; } } -Steve
Aug 09 2020
next sibling parent reply lexxn <aleksandar.m.nikolov gmail.com> writes:
On Sunday, 9 August 2020 at 12:24:05 UTC, Steven Schveighoffer 
wrote:
 On 8/9/20 5:16 AM, lexxn wrote:
 I'm trying to get the factory pattern going with classes
 class A {}
 
 class B {}
 
 class C {}
 
 auto getClassById(uint id)
 {
      if (id == 0) {
          return cast(A)Object.factory("A");
      } else if(id == 1) {
          return cast(B)Object.factory("B");
      } else {
          return cast(C)Object.factory("C");
      }
 }
 
 I'm getting 2 errors:
 main.d(69): Error: Expected return type of main.A, not main.B:
 main.d(67):        Return type of main.Ainferred here.
Change your return type to Object.
 Also is it possible to completely skip the getClassById 
 function and if I've and array string classes = ["A", "B"] to 
 just cast(classes[0])Object.factory(classes[0]);. I understand 
 that I need to cast classes[0].
This won't work. If you know what your class is going to be, I'd just import the file that contains it and avoid the whole Object.factory deal. It's going to go away anyways. In other words: Object getClassById(uint id) { if (id == 0) { return new A; } else if(id == 1) { return new B; } else { return new C; } } -Steve
I assume that the correct syntax for the getClassById is Object getClassById(uint id) { if (id == 0) { return new A(); } else if (id == 1) { return new B(); } else { return new C(); } } or maybe I'm wrong. This way if I try auto myClass = getClassById(0) and if I've a method in A,B&C classes when I try to call it with myClass I get no property methodName for type object.Object.
Aug 09 2020
next sibling parent reply =?UTF-8?Q?Ali_=c3=87ehreli?= <acehreli yahoo.com> writes:
On 8/9/20 7:27 AM, lexxn wrote:

 I assume that the correct syntax for the getClassById is
 Object getClassById(uint id) {
      if (id == 0) {
          return new A();
      } else if (id == 1) {
          return new B();
      } else {
          return new C();
      }
 }
 or maybe I'm wrong.
Because those example classes are not a part of a hierarchy, their common interface is Object. That is the only way to get the code compile.
 This way if I try auto myClass = getClassById(0) and
 if I've a method in A,B&C classes when I try to call it with myClass I
 get no property methodName for type object.Object.
If methodName() is a virtual function of your hierarchy, then normally it is a part of an interface that all those classes implement and the return type is that common ancestor. Here is a working example: module deneme; import std.stdio; interface I { void methodName(); } class A : I { void methodName() { writeln("A"); } } class B : I { void methodName() { writeln("B"); } } class C : I { void methodName() { writeln("C"); } } I getClassById(uint id) { if (id == 0) { return cast(A)Object.factory("deneme.A"); } else if(id == 1) { return cast(B)Object.factory("deneme.B"); } else { return cast(C)Object.factory("deneme.C"); } } void main() { auto o = getClassById(1); o.methodName(); } Ali
Aug 09 2020
next sibling parent lexxn <aleksandar.m.nikolov gmail.com> writes:
On Sunday, 9 August 2020 at 15:56:31 UTC, Ali Çehreli wrote:
 On 8/9/20 7:27 AM, lexxn wrote:

 module deneme;

 import std.stdio;

 interface I {
   void methodName();
 }

 class A : I {
   void methodName() {
     writeln("A");
   }
 }

 class B : I {
   void methodName() {
     writeln("B");
   }
 }

 class C : I {
   void methodName() {
     writeln("C");
   }
 }

 I getClassById(uint id)
 {
     if (id == 0) {
         return cast(A)Object.factory("deneme.A");
     } else if(id == 1) {
         return cast(B)Object.factory("deneme.B");
     } else {
         return cast(C)Object.factory("deneme.C");
     }
 }

 void main() {
   auto o = getClassById(1);
   o.methodName();
 }

 Ali
This is the solution I will use, at least for now. Thank you Ali.
Aug 09 2020
prev sibling next sibling parent reply lexxn <aleksandar.m.nikolov gmail.com> writes:
On Sunday, 9 August 2020 at 15:56:31 UTC, Ali Çehreli wrote:
 On 8/9/20 7:27 AM, lexxn wrote:

 I getClassById(uint id)
 {
     if (id == 0) {
         return cast(A)Object.factory("deneme.A");
     } else if(id == 1) {
         return cast(B)Object.factory("deneme.B");
     } else {
         return cast(C)Object.factory("deneme.C");
     }
 }

 void main() {
   auto o = getClassById(1);
   o.methodName();
 }

 Ali
Btw is it possible to pass a property to the constructor, if I've one declared, in the factory? I'm talking about this piece cast(A)Object.factory("deneme.A")
Aug 10 2020
parent =?UTF-8?Q?Ali_=c3=87ehreli?= <acehreli yahoo.com> writes:
On 8/10/20 8:38 AM, lexxn wrote:

 Btw is it possible to pass a property to the constructor, if I've one 
 declared, in the factory? I'm talking about this piece 
 cast(A)Object.factory("deneme.A")
I think you mean "parameter". No, Object.factory creates the object with its default constructor. Ali
Aug 10 2020
prev sibling parent Martin <martin.brzenska googlemail.com> writes:
On Sunday, 9 August 2020 at 15:56:31 UTC, Ali Çehreli wrote:
 module deneme;

 import std.stdio;

 interface I {
   void methodName();
 }
 ...
 I getClassById(uint id)
 {
     if (id == 0) {
         return cast(A)Object.factory("deneme.A");
     } else if(id == 1) {
         return cast(B)Object.factory("deneme.B");
     } else {
         return cast(C)Object.factory("deneme.C");
     }
 }

 void main() {
   auto o = getClassById(1);
   o.methodName();
 }
Why not simply do?
I getClassById(uint id)
{
    if (id == 0) {
        return new A();
    } else if(id == 1) {
        return new B();
    } else {
        return new C();
    }
}
Then you can also pass parameters to the constructors or call further factories to create them, as long as they return a `I`-compatible type.
Aug 10 2020
prev sibling parent Steven Schveighoffer <schveiguy gmail.com> writes:
On 8/9/20 10:27 AM, lexxn wrote:
 On Sunday, 9 August 2020 at 12:24:05 UTC, Steven Schveighoffer wrote:
 Object getClassById(uint id)
 {
     if (id == 0) {
         return new A;
     } else if(id == 1) {
         return new B;
     } else {
         return new C;
     }
 }
I assume that the correct syntax for the getClassById is Object getClassById(uint id) {     if (id == 0) {         return new A();     } else if (id == 1) {         return new B();     } else {         return new C();     } } or maybe I'm wrong.
If the constructor has no parameters, classes can be new'd without parentheses, so your modification results in identical code as my example. -Steve
Aug 09 2020
prev sibling parent reply lexxn <aleksandar.m.nikolov gmail.com> writes:
On Sunday, 9 August 2020 at 12:24:05 UTC, Steven Schveighoffer 
wrote:
 If you know what your class is going to be, I'd just import the 
 file that contains it and avoid the whole Object.factory deal. 
 It's going to go away anyways.
Not sure if it's a good idea in my case. I'm going to be using all of the classes eventually in my loop, but I just need to initialize them in a conditional way depending on the use case.
Aug 09 2020
parent Steven Schveighoffer <schveiguy gmail.com> writes:
On 8/9/20 10:58 AM, lexxn wrote:
 On Sunday, 9 August 2020 at 12:24:05 UTC, Steven Schveighoffer wrote:
 If you know what your class is going to be, I'd just import the file 
 that contains it and avoid the whole Object.factory deal. It's going 
 to go away anyways.
Not sure if it's a good idea in my case. I'm going to be using all of the classes eventually in my loop, but I just need to initialize them in a conditional way depending on the use case.
My point is -- it's a good idea to not use Object.factory, because it's going to go away. It doesn't work in all cases anyway. -Steve
Aug 09 2020