Design pattern analysis - Abstract Factory Abstract Factory Pattern

meaning

  • And factory method pattern comparison, the concept is somewhat different. Abstract parts, product abstract, abstract factory. With parts to assemble the product, the product is assembled out of a complete product.
  • Since a complete product requires multiple parts, then each concrete factory can produce naturally we need a variety of parts simultaneously (refer to the factory there are several createXXXmethods).
  • What emphasis on abstract class product family, product abstract class is meaningless. This is simply because the inheritance tree, there is an abstract base class for more specific differentiation of two kinds of abstract base class nothing.
  • Perhaps you will use reflection or generics, but keep in mind that the purpose of using these technologies is to let the client know the specific parts or specific class of product categories, not to virtuoso.

UML 图

Here Insert Picture Description
Still feel gives practical examples of UML diagrams easier to understand it. Here to explain the meaning of these classes:

  • nonConcrete bag abstract class; Concrete classes specific package.
  • Part mobile phone phone, mobile phone shell phoneShell, phone film phoneFilm. When put to the phone shell, paste film, considered this a complete product.
  • phoneShell and phoneFilm inherited the same interface item, because they all belong to a class of something fitting.
  • And oppo mobile phones supporting assume that soft shell softShell, non-full-screen film almostFilm; vivo and phone support is hard hardShell, full-screen film fullFilm.
  • Specific classes of these three components can have a more specific description, given by the constructor.

Sample Code

First nonConcrete package abstract class:

package nonConcrete;

//item.java file
interface item {
    String attribute();
}

//这是另一个文件的内容,但此处省略了package nonConcrete。后面将作同样处理,即省略package语句。
//phoneShell.java file
public abstract class phoneShell implements item{
    protected String whichShell;
    protected phoneShell(String in){
        whichShell = in;
    }
}

//phoneFilm.java file
public abstract class phoneFilm implements item{
    protected String whichFilm;
    protected phoneFilm(String in){
        whichFilm = in;
    }
}

//phone.java file
public abstract class phone {
    public String whichVision;
    public phoneShell myShell;
    public phoneFilm myFilm;
    protected phone(String in){
        whichVision = in;
    }
    public phone addShell(phoneShell shell){
        myShell = shell;
        return this;
    }
    public phone addFilm(phoneFilm film){
        myFilm = film;
        return this;
    }
    public abstract void boot();//开机
}

//factory.java file
public abstract class factory {
    public static factory getFactory(String classname){
        factory f = null;
        try {
            f = (factory)Class.forName(classname).newInstance();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
        return f;
    }
    public abstract phoneShell createShell(String shellType);
    public abstract phoneFilm createFilm(String filmType);
    public abstract phone createPhone(String phoneType);
}
  • Note that abstract class phone handset has three member variables, but only constructor to initialize one. The remaining two members to additionally function to add two members, and in order to facilitate the flow operation, these two functions return this.
  • Abstract factory class factory defined the three abstract methods that return the three kinds of parts. There is also a static method getFactory, for reflecting an object factory class specific. This will avoid the client understands concrete factory class.
  • If you do not have a reflection on, I think can only be resolved through internal classes and static: static inner classes to inherit and implement factory, because there should not be held outside the class object Logically reference (or use in static context anonymous inner classes in the context of this case does not hold the outer class object reference); then instantiate static inner classes and instances upcast assigned to a factory type of static member variables.

Then concrete is concrete class package:

package concrete;

//softShell.java file
import nonConcrete.phoneShell;

class softShell extends phoneShell {
    softShell(String type){
        super(type);
    }
    @Override
    public String attribute(){//实现了item接口的方法
        return this.whichShell+"软壳";
    }
}

//hardShell.java file
import nonConcrete.phoneShell;

class hardShell extends phoneShell {
    hardShell(String type){
        super(type);
    }
    @Override
    public String attribute(){
        return this.whichShell+"硬壳";
    }
}

//almostFilm.java file
import nonConcrete.phoneFilm;

class almostFilm extends phoneFilm {
    almostFilm(String type){
        super(type);
    }
    public String attribute(){
        return this.whichFilm+"非全屏膜";
    }
}

//fullFilm.java file
import nonConcrete.phoneFilm;

class fullFilm extends phoneFilm {
    fullFilm(String type){
        super(type);
    }
    public String attribute(){
        return this.whichFilm+"全屏膜";
    }
}

//oppoPhone.java file
import nonConcrete.phone;

class oppoPhone extends phone {
    oppoPhone(String in){
        super(in);
    }
    @Override
    public void boot(){
        System.out.println("oppo"+this.whichVision+"手机:带有"+this.myShell.attribute()+
                "和"+this.myFilm.attribute());
    }
}

//vivoPhone.java file
import nonConcrete.phone;

class vivoPhone extends phone {
    vivoPhone(String in){
        super(in);
    }
    @Override
    public void boot(){
        System.out.println("vivo"+this.whichVision+"手机:带有"+this.myShell.attribute()+
                "和"+this.myFilm.attribute());
    }
}

//oppoFactory.java file
import nonConcrete.*;

public class oppoFactory extends factory {
    public phoneShell createShell(String shellType){
        return new softShell(shellType);
    }
    public phoneFilm createFilm(String filmType){
        return new almostFilm(filmType);
    }
    public phone createPhone(String phoneType){
        return new oppoPhone(phoneType);
    }
}

//vivoFactory.java file
import nonConcrete.*;

public class vivoFactory extends factory {
    public phoneShell createShell(String shellType){
        return new hardShell(shellType);
    }
    public phoneFilm createFilm(String filmType){
        return new fullFilm(filmType);
    }
    public phone createPhone(String phoneType){
        return new vivoPhone(phoneType);
    }
}

Note that two concrete factory class privileges modifier must be public, if not, then the following factory oppoFac = factory.getFactory("concrete.oppoFactory");would be an error java.lang.IllegalAccessException: Class nonConcrete.factory can not access a member of class concrete.oppoFactory with modifiers "", because reflection is carried out in a static method of nonConcrete.factory, it is necessary here to access to concrete.oppoFactory. But those parts specific permission class may be a default, because they only need to be accessed like concrete factory class.
Look at the way the call stack error, chasing at the source:

	at sun.reflect.Reflection.ensureMemberAccess(Reflection.java:102)
	at java.lang.Class.newInstance(Class.java:436)
//Reflection.java
    public static void ensureMemberAccess(Class<?> var0, Class<?> var1, Object var2, int var3) throws IllegalAccessException {
        if (var0 != null && var1 != null) {
            if (!verifyMemberAccess(var0, var1, var2, var3)) {//调用此函数返回了假,说明没有通过验证
                throw new IllegalAccessException("Class " + var0.getName() + " can not access a member of class " + var1.getName() + " with modifiers \"" + Modifier.toString(var3) + "\"");
            }
        } else {
            throw new InternalError();
        }
    }
    public static boolean verifyMemberAccess(Class<?> var0, Class<?> var1, Object var2, int var3) {
    	//var0是调用者,var1是被实例化者
        boolean var4 = false;
        boolean var5 = false;
        if (var0 == var1) {
            return true;
        } else {
            if (!Modifier.isPublic(getClassAccessFlags(var1))) {//先检查被实例者是不是public的
                var5 = isSameClassPackage(var0, var1);//再检查是不是同一个包
                var4 = true;
                if (!var5) {
                    return false;
                }
            }
     //后面还有,不贴上来了   
     }

Then package the default test class:

import nonConcrete.*;

public class Main {
    public static void main(String[] args) {
        factory oppoFac = factory.getFactory("concrete.oppoFactory");
        phoneShell oppoS = oppoFac.createShell("透明的");
        phoneFilm oppoF = oppoFac.createFilm("抗蓝光的");
        phone oppo = oppoFac.createPhone("R15").addShell(oppoS).addFilm(oppoF);//组装产品
        oppo.boot();

        factory vivoFac = factory.getFactory("concrete.vivoFactory");
        phoneShell vivoS = vivoFac.createShell("抗摔的");
        phoneFilm vivoF = vivoFac.createFilm("高清的");
        phone vivo = vivoFac.createPhone("X27").addShell(vivoS).addFilm(vivoF);
        vivo.boot();
    }
}/*output:
oppoR15手机:带有透明的软壳和抗蓝光的非全屏膜
vivoX27手机:带有抗摔的硬壳和高清的全屏膜
*/

As can be seen from the test class imported packages, the client does not need to know any specific classes, of course, there is also thanks to the credit reflection.

Advantages and disadvantages

  • When the parts meet the abstract class does not need to increase [opening and closing] principle, only need to add specific parts class and the concrete factory class can be.
  • When the abstract class will need to increase the part opening and closing principle is not eligible [], concrete factory class exists at this time needs to be increased function. For the examples in this article, the situation may also need phone camera film to the factory.
  • The above points are summarized as follows: the tilt of the principle of opening and closing.

Scenarios

  • In the product category also you need to have the concept of parts class.
  • When the factory class needs to have several ways to create different types of products.
Published 171 original articles · won praise 130 · views 280 000 +

Guess you like

Origin blog.csdn.net/anlian523/article/details/100181808