设计模式-简单工厂模式

一、定义:由一个工厂对象决定创建出哪一种产品类的实例

二、类型:创建型,但不属于GOF23种设计模式

三、适用场景:

  工厂类负责创建的对象比较少

  客户端(应用层)只知道传入工厂类的参数,对于如何创建对象(逻辑)不关心。

四、优点:

  只需要传入一个正确的参数,就可以获取你所需要的对象,而无须知道其创建细节

五、缺点:

  工厂类的职责相对过重,增加新的产品需要修改工厂类的判断逻辑,违背开闭原则

六、Coding

1.创建Video抽象类

public abstract class Video {
    public abstract void  produce();
}  

里面包含一个抽象方法 produce代表录制视频

2.创建JavaVideo类,继承Video抽象类

public class JavaVideo  extends  Video{
    @Override
    public void produce() {
        System.out.println("录制Java视频");
    }
}

  

3. 创建AndroidVideo类,继承Video抽象类

public class AndroidVideo  extends  Video{
    @Override
    public void produce() {
        System.out.println("录制Android视频");
    }
}

  

4. 创建工厂类

public class VideoFactory {

    public Video getVideo(String type){
        if("java".equalsIgnoreCase(type)){
            return  new JavaVideo();
        }else if("android".equalsIgnoreCase(type)){
            return  new AndroidVideo();
        }

        return  null;
    }
}

  

5. 创建测试类或者应用类

public class Test {
    public static void main(String[] args) {
        VideoFactory videoFactory = new VideoFactory();
        Video video = videoFactory.getVideo("java");
        if(video == null){
            return;
        }
        video.produce();
    }
}

  

6. UML图如下:

7. 缺点: 如果要增加Ios视频录制,则要修改工厂类的判断逻辑以及增加IosVideo类

   这样违背开放闭合原则

  改进方法: 将工厂类中通过字符创建实例的方法改为通过反射创建实例,这样增加IosVideo时,工厂类就不需要做修改

  改进后的VideoFactory 类

 public Video getVideo(Class c)  {
       Video video = null;
        try {
            video = (Video) Class.forName(c.getName()).newInstance();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
        return  video;
    }

  测试类的调用方法

public class Test {

    public static void main(String[] args) {
        VideoFactory videoFactory = new VideoFactory();
        Video video = videoFactory.getVideo(JavaVideo.class);
        if(video == null){
            return;
        }
        video.produce();
    }
}

  

七、JDK源码中使用简单工厂模式的地方

1. Calendar类

public static Calendar getInstance(TimeZone zone,
                                       Locale aLocale)
    {
        return createCalendar(zone, aLocale);
    }

createCalendar方法  

 private static Calendar createCalendar(TimeZone zone,  Locale aLocale)
    {
        Calendar cal = null;

        String caltype = aLocale.getUnicodeLocaleType("ca");
        if (caltype == null) {
            // Calendar type is not specified.
            // If the specified locale is a Thai locale,
            // returns a BuddhistCalendar instance.
            if ("th".equals(aLocale.getLanguage())
                    && ("TH".equals(aLocale.getCountry()))) {
                cal = new BuddhistCalendar(zone, aLocale);
            } else {
                cal = new GregorianCalendar(zone, aLocale);
            }
        } else if (caltype.equals("japanese")) {
            cal = new JapaneseImperialCalendar(zone, aLocale);
        } else if (caltype.equals("buddhist")) {
            cal = new BuddhistCalendar(zone, aLocale);
        } else {
            // Unsupported calendar type.
            // Use Gregorian calendar as a fallback.
            cal = new GregorianCalendar(zone, aLocale);
        }

        return cal;
    }

 根据caltype类型,创建对应的实例。

uml图

 

2. logback中ILoggerFactory.class中的getLogger方法

public final Logger getLogger(String name) {
        if(name == null) {
            throw new IllegalArgumentException("name argument cannot be null");
        } else if("ROOT".equalsIgnoreCase(name)) {
            return this.root;
        } else {
            int i = 0;
            Logger logger = this.root;
            Logger childLogger = (Logger)this.loggerCache.get(name);
            if(childLogger != null) {
                return childLogger;
            } else {
                int h;
                do {
                    h = LoggerNameUtil.getSeparatorIndexOf(name, i);
                    String childName;
                    if(h == -1) {
                        childName = name;
                    } else {
                        childName = name.substring(0, h);
                    }

                    i = h + 1;
                    synchronized(logger) {
                        childLogger = logger.getChildByName(childName);
                        if(childLogger == null) {
                            childLogger = logger.createChildByName(childName);
                            this.loggerCache.put(childName, childLogger);
                            this.incSize();
                        }
                    }

                    logger = childLogger;
                } while(h != -1);

                return childLogger;
            }
        }
    }

  根据name,获得哪一个log

原文地址:https://www.cnblogs.com/linlf03/p/9741060.html