Introduction: It is a very detailed thing to be able to use design mode in normal coding, but it is also the beginning of advanced coding. Different people write the same code at different levels. Gdutxiaoxu is an old friend of gdutxiaoxu. Gdutxiaoxu blog:http://blog.csdn.net/gdutxiaoxu/. Take a look at the text:

Write in front, this blog is not much significance to the old drivers, the old drivers do not need to see, for the novice or have great practical value.

Have you ever worked on a project where you used the open source framework ImageLoader and now you want to use Picasso or Glide? Is it code by code?

Of course, if the project uses less ImageLoader corresponding methods, that is ok, but once the project is larger, it will be a lot of work, estimated at least a few days, tired to say nothing, at least meaningless, so what to do? Don’t worry, here’s the explanation.

The first way

This is a method that most people will use, encapsulating it directly into a utility class, extracting the common parameters, and then modifying the specific implementation of the utility class if you want to change it later

public class ImageLoaderUtils { public static void loadImageView(Context mContext, String url, ImageView mImageView) { Picasso.with(mContext).load(url).into(mImageView); }}Copy the code

If we don’t want to use Picasso in our project and we want to use Glide in our project, we just need to modify the concrete implementation of the method in the ImageLoaderUtils class. The code is as follows

Public class ImageLoaderUtils {/** * specifies the size of the loaded image ** @param mContext * @param URL image path * @param mImageView control */ public static void loadImageView(Context mContext, String url, ImageView mImageView) { // Picasso.with(mContext).load(url).into(mImageView); Glide.with(mContext).load(url).into(mImageView); }}Copy the code

Looking at the code above, I’m sure most of you know that if we don’t encapsulate, we’ll have to find each class file where Picasso’s corresponding method is used and then replace it, which can be a lot of work. Wouldn’t it be convenient to encapsulate and just change the implementation of the methods in the utility class? Do you think this article is over? Not yet. Here’s another method, which is more elegant.

That is to use the simple factory pattern.


Simple Factory model

define

Simple Factory Pattern: Also known as Static Factory Method Pattern, it belongs to the class creation Pattern. In the simple factory pattern, you can return instances of different classes depending on the parameters. The simple factory pattern specifically defines a class that is responsible for creating instances of other classes, which usually have a common parent class. Simply put, it is used to create objects that have the same base class

Type of UML diagram



Character is introduced

As can be seen from the UML diagram above, there are altogether three roles Factory, Product and ConcreteProuct, in which Factory depends on Product

Product: The base class of a Product, usually served by an abstract class or interface, that unifies the interface without concern for implementation details

ConcreteProduct: Concrete implementation class for Product

Factory: Factory class, used to create objects that can return different Product objects depending on the parameters and encapsulate the implementation logic inside

Using the step

From the above analysis, we know that the simple factory pattern generally requires three steps

  • Common characteristics of abstract products, defined as an interface or abstract class

  • Concrete implementation of ConcreteProduct

  • To realize the Factory

Now let’s see how it can be used to replace image frames


Simple factory pattern application – a few lines of code to change the image frame

Let’s first take a look at the class UML diagram to deepen our understanding



In the first step, we define an interface, IimageListener, to unify parameters

public interface IimageListener {
    void display(Context context, ImageView imageView, 
                 String url, int progressId, int errorId,
                 Object tag);
    void display(Context context, ImageView imageView, 
                 String url, int progressId, int errorId);
    void display(Context context, ImageView imageView, 
                 String url, int progressId);
    void display(Context context, ImageView imageView, 
                 String url);
    void display(Context context, ImageView imageView, Uri uri);
 }Copy the code

Second, let’s write a concrete implementation of GlideRequest and PicassoRequest

public class GlideRequest implements IimageListener { @Override public void display(Context context, ImageView imageView, String url, int progressId, int errorId, Object tag) { DrawableTypeRequest<String> load = Glide.with(context).load(url); if (progressId ! = -1) { load.placeholder(progressId).centerCrop(); } else { load.placeholder(new ColorDrawable(Color.GRAY)); } if (errorId ! = -1) { load.error(errorId); }else{ load.error(R.drawable.ic_error); } load.into(imageView); } @Override public void display(Context context, ImageView imageView, String url, int progressId, int errorId) { display(context, imageView, url, progressId, errorId, null); } @Override public void display(Context context, ImageView imageView, String url, int progressId) { display(context, imageView, url, progressId, -1, null); } @Override public void display(Context context, ImageView imageView, String url) { display(context, imageView, url, -1, -1, null); } @Override public void display(Context context, ImageView imageView, Uri uri) { DrawableTypeRequest<Uri> load = Glide.with(context).load(uri); load.into(imageView); }}Copy the code

PicassoRequest

public class PicassoRequest implements IimageListener { @Override public void display(Context context, ImageView imageView, String url, int progressId, int errorId, Object tag) { Picasso.with(context) .load(url) .placeholder(progressId) .error(errorId) .tag(tag) .into(imageView); } @Override public void display(Context context, ImageView imageView, String url, int progressId, int errorId) { Picasso.with(context) .load(url) .placeholder(progressId) .error(errorId) .into(imageView); } @Override public void display(Context context, ImageView imageView, String url, int progressId) { Picasso.with(context) .load(url) .placeholder(progressId) .into(imageView); } @Override public void display(Context context, ImageView imageView, String url) { Picasso.with(context).load(url).into(imageView); } @Override public void display(Context context, ImageView imageView, Uri uri) { Picasso.with(context).load(uri).into(imageView); }}Copy the code

The third step is to write the implementation of the factory class ImageRequestManager. As you can see, we can return different instances based on different parameters to decide whether to use Picasso or Glide

public class ImageRequestManager { public static final String type_Glide="Glide"; public static final String type_Picasso="Picasso"; public static final String type_default =type_Glide; private ImageRequestManager(){ } public static IimageListener getRequest(){ return getRequest(type_default); } public static IimageListener getRequest(String type){ switch (type){ case type_Glide: return new GlideRequest(); case type_Picasso: return new PicassoRequest(); default: return new GlideRequest(); }}}Copy the code

Finally, if we want to load images in the future, we can simply call the following method, which is straightforward, and we don’t have to worry about replacing frames

ImageRequestManager
                  .getRequest()
                  .display(mContext, imageView, imageUrl);Copy the code

discuss

Scenario 1: I used to use Glide frame. now I want to use Picasso frame. how do I do that?

Just change the String TypeDefault =typeGlide in ImageRequestManager to String TypeDefault =typePicasso.

//public static final String type_default =type_Glide;
public static final String type_default =type_Picasso;Copy the code

Situation 2: Some people will say that they usually only use one frame for loading images in their projects, either Picasso or Glide. You have increased the size of APK by using both frames. What should you do then? It’s actually quite simple

If you only want to use Picasso, remove the renderer of Glide, and if you only want to use Glide, remove the renderer of Glide, but leave the null method as it is recommended that you do not need to change the factory class ImageRequestManager logic.


Summary of the simple factory pattern

  • The coupling degree of the system is reduced by combining object creation with object business logic analysis

  • The point of the simple factory pattern is that when you need something, you can just pass in the right argument and get the object you need without knowing the details of how it was created. For the convenience of the caller, we can add a default parameter to the factory class so that we don’t have to pass it in every time we call it

  • Know from the above example, we know, most business logic inside the factory, if the factory class needs to create the object is not much, simple factory method pattern is still has a big advantage, and if you need to create a lot of objects, that factory there is no doubt to increase a lot of case statement, this will cause the factory class responsibility is too heavy. It breaks the singleness of the class.

To sum up:

The greatest advantage of simple factory pattern is to realize the use of object creation and separation, the object creation to the specialized factory class is responsible for, but the biggest drawback is that the factory class is not flexible, adding new specific products need to modify the factory class judgment logic code, and are too many products, the factory method code will be very complicated.

The simple factory pattern applies when the factory class is responsible for creating fewer objects; The client only knows the parameters passed into the factory class and does not care how the object is created.


extension

Read the above article, for Volley, OKhttp and other simple network framework package, you are not also thought of what, should know how to package it.

Do you have any ideas about Retrofit encapsulation? Retrofit’s return object is an Observable<>, which is quite different from other web frameworks. In fact, it can be handled roughly. I won’t discuss it here, but you can try it yourself if you are interested.


digression

Great oaks from little acorns grow, for the program ape of us, we must do more hands-on practice, I believe many students see here, have a basic grasp, but there are a lot of students do not start to practice, so, a few days passed, half understand, finally forget, and this is the watershed. Ha ha, that’s it.


Finally give the github address, the above small project is I usually have no time to write for fun.

Making address: https://github.com/gdutxiaoxu/FunAPP

It was also written by Gdutxiaoxu.


The first time to get blog update reminder, and more Android, small program dry goods, source code analysis, the latest open source project recommendation, welcome to pay attention to my wechat public number, scan the qr code below or long press to identify the QR code, you can pay attention to.