2 заметки с тегом


Interview: Factory Method and Abstract Factory, on each other

Yuri D.: Wow, an interview with two patterns at once! This is a first for us.

Factory Method: Yeah, I’m not so sure I like being lumped in with Abstract Factory, you know. Just because we’re both factory patterns doesn’t mean we shouldn’t get our own interviews.

Yuri D.: Don’t be miffed, we wanted to interview you together so we could help clear up any confusion about who’s who for the readers. You do have similarities, and I’ve heard that people sometimes get you confused.

Abstract Factory: It is true, there have been times I’ve been mistaken for Factory Method, and I know you’ve had similar issues, Factory Method. We’re both really good at decoupling applications from specific implementations; we just do it in different ways. So I can see why people might sometimes get us confused.

Factory Method: Well, it still ticks me off. After all, I use classes to create and you use objects; that’s totally different!

Yuri D.: Can you explain more about that, Factory Method?

Factory Method: Sure. Both Abstract Factory and I create objects — that’s our jobs. But I do it through inheritance...

Abstract Factory: ...and I do it through object composition.

Factory Method: Right. So that means, to create objects using Factory Method, you need to extend a class and provide an implementation for a factory method.

Yuri D.: And that factory method does what?

Factory Method: It creates objects, of course! I mean, the whole point of the Factory Method Pattern is that you’re using a subclass to do your creation for you. In that way, clients only need to know the abstract type they are using, the subclass worries about the concrete type. So, in other words, I keep clients decoupled from the concrete types.

Abstract Factory: And I do too, only I do it in a different way.

Yuri D.: Go on, Abstract Factory... you said something about object composition?

Abstract Factory: I provide an abstract type for creating a family of products. Subclasses of this type define how those products are produced. To use the factory, you instantiate one and pass it into some code that is written against the abstract type. So, like Factory Method, my clients are decoupled from the actual concrete products they use.

Yuri D.: Oh, I see, so another advantage is that you group together a set of related products.

Abstract Factory: That’s right.

Yuri D.: What happens if you need to extend that set of related products to, say, add another one? Doesn’t that require changing your interface?

Abstract Factory: That’s true; my interface has to change if new products are added, which I know people don’t like to do...

Factory Method:

Abstract Factory: What are you snickering at, Factory Method?

Factory Method: Oh, come on, that’s a big deal! Changing your interface means you have to go in and change the interface of every subclass! That sounds like a lot of work.

Abstract Factory: Yeah, but I need a big interface because I am used to creating entire families of products. You’re only creating one product, so you don’t really need a big interface, you just need one method.

Yuri D.: Abstract Factory, I heard that you often use factory methods to implement your concrete factories?
Abstract Factory: Yes, I’ll admit it, my concrete factories often implement a factory method to create their products. In my case, they are used purely to create products...

Factory Method: ...while in my case I usually implement code in the abstract creator that makes use of the concrete types the subclasses create.

Yuri D.: It sounds like you both are good at what you do. I’m sure people like having a choice; after all, factories are so useful, they’ll want to use them in all kinds of different situations. You both encapsulate object creation to keep applications loosely coupled and less dependent on implementations, which is really great, whether you’re using Factory Method or Abstract Factory. May I allow you each a parting word?

Abstract Factory: Thanks. Remember me, Abstract Factory, and use me whenever you have families of products you need to create and you want to make sure your clients create products that belong together.

Factory Method: And I’m Factory Method; use me to decouple your client code from the concrete classes you need to instantiate, or if you don’t know ahead of time all the concrete classes you are going to need. To use me, just subclass me and implement my factory method!

2017   Factory Pattern   OOP   Patterns

To trait, or not to trait?

Whenever you implement a reusable collection of behavior, you will have to decide whether you want to use a trait or an abstract class. There is no firm rule, but this section contains a few guidelines to consider.

If the behavior will not be reused, then make it a concrete class. It is not reusable behavior after all.

If it might be reused in multiple, unrelated classes, make it a trait. Only traits can be mixed into different parts of the class hierarchy.

If you want to inherit from it in Java code, use an abstract class. Since traits with code do not have a close Java analog, it tends to be awkward to inherit from a trait in a Java class. Inheriting from a Scala class, meanwhile, is exactly like inheriting from a Java class. As one exception, a Scala trait with only abstract members translates directly to a Java interface, so you should feel free to define such traits even if you expect Java code to inherit from it. See Chapter 29 for more information on working with Java and Scala together.

If you plan to distribute it in compiled form, and you expect outside groups to write classes inheriting from it, you might lean towards using an abstract class. The issue is that when a trait gains or loses a member, any classes that inherit from it must be recompiled, even if they have not changed. If outside clients will only call into the behavior, instead of inheriting from it, then using a trait is fine.

If efficiency is very important, lean towards using a class. Most Java runtimes make a virtual method invocation of a class member a faster operation than an interface method invocation. Traits get compiled to interfaces and therefore may pay a slight performance overhead. However, you should make this choice only if you know that the trait in question constitutes a performance bottleneck and have evidence that using a class instead actually solves the problem.

If you still do not know, after considering the above, then start by making it as a trait. You can always change it later, and in general using a trait keeps more options open.

2017   OOP   Traits