二 Java设计模式解析(工厂模式)

一 简单工厂

1️⃣概念

定义:由一个工厂对象决定创建出哪一种产品类的实例;
类型:创建型,但不属于GOF23种设计模式;

2️⃣适用场景

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

3️⃣优点

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

4️⃣缺点

工厂类的职责相对过重,增加新的产品需要修改工厂类的判断逻辑,违背了开闭原则;
无法形成基于继承的等级结构;

5️⃣简单工厂Coding

①创建Video抽象类

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

②创建实现类来实现Video类

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

③创建简单工厂类

public class 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 Video getVideo(String type){
        if("java".equalsIgnoreCase(type)){
            return new JavaVideo();
        }else if("python".equalsIgnoreCase(type)){
            return new PythonVideo();
        }
        return null;
    }
}

④编写测试类

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

        VideoFactory videoFactory = new VideoFactory();
        Video video = videoFactory.getVideo(JavaVideo.class);
        if(video == null){
            return;
        }
        video.produce();
    }
}

⑤UML类图
6️⃣应用简单工厂的JDK类(java.util.calendar源码)
/**
     * Gets a calendar using the default time zone and locale. The
     * Calendar returned is based on the current time
     * in the default time zone with the default
     * {@link Locale.Category#FORMAT FORMAT} locale.
     *
     * @return a Calendar.
     */
    public static Calendar getInstance()
    {
        return createCalendar(TimeZone.getDefault(), Locale.getDefault(Locale.Category.FORMAT));
    }
private static Calendar createCalendar(TimeZone zone,
                                           Locale aLocale)
    {
        CalendarProvider provider =
            LocaleProviderAdapter.getAdapter(CalendarProvider.class, aLocale)
                                 .getCalendarProvider();
        if (provider != null) {
            try {
                return provider.getInstance(zone, aLocale);
            } catch (IllegalArgumentException iae) {
                // fall back to the default instantiation
            }
        }

        Calendar cal = null;

        if (aLocale.hasExtensions()) {
            String caltype = aLocale.getUnicodeLocaleType("ca");
            if (caltype != null) {
                switch (caltype) {
                case "buddhist":
                cal = new BuddhistCalendar(zone, aLocale);
                    break;
                case "japanese":
                    cal = new JapaneseImperialCalendar(zone, aLocale);
                    break;
                case "gregory":
                    cal = new GregorianCalendar(zone, aLocale);
                    break;
                }
            }
        }
        if (cal == null) {
            // If no known calendar type is explicitly specified,
            // perform the traditional way to create a Calendar:
            // create a BuddhistCalendar for th_TH locale,
            // a JapaneseImperialCalendar for ja_JP_JP locale, or
            // a GregorianCalendar for any other locales.
            // NOTE: The language, country and variant strings are interned.
            if (aLocale.getLanguage() == "th" && aLocale.getCountry() == "TH") {
                cal = new BuddhistCalendar(zone, aLocale);
            } else if (aLocale.getVariant() == "JP" && aLocale.getLanguage() == "ja"
                       && aLocale.getCountry() == "JP") {
                cal = new JapaneseImperialCalendar(zone, aLocale);
            } else {
                cal = new GregorianCalendar(zone, aLocale);
            }
        }
        return cal;
    }

二 工厂方法

1️⃣概念

定义:定义一个创建对象的接口,但让实现接口的这个类来决定实例化哪个类,工厂方法让类的实例化推迟到子类中进行;
类型:创建性

2️⃣适用的场景

创建对象需要大量重复的代码;
客户端(应用层)不依赖于产品类实例如何被创建 实现等细节;
一个类通过其子类来指定创建哪个对象;

3️⃣优点

用户只需关心所需产品对应的工厂,无需关心创建细节;
加入新产品符合开闭原则,提高可扩展性;

4️⃣缺点

类的个数容易过多,增加复杂度;
增加了系统的抽象性和理解难度;

5️⃣工厂方法Coding

①创建产品类抽象类Video

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

②创建具体的产品类来实现抽象类

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

③创建产品抽象工厂类VideoFactory

public abstract class VideoFactory {
    public abstract Video getVideo();
}

④创建具体的产品工厂类实现产品抽象工厂

public class FEVideoFactory extends VideoFactory{
    @Override
    public Video getVideo() {
        return new FEVideo();
    }
}
public class JavaVideoFactory extends VideoFactory {
    @Override
    public Video getVideo() {
        return new JavaVideo();
    }
}
public class PythonVideoFactory extends VideoFactory {
    @Override
    public Video getVideo() {
        return new PythonVideo();
    }
}

⑤创建测试类

public class Test {
    public static void main(String[] args) {
        VideoFactory videoFactory = new PythonVideoFactory();
        VideoFactory videoFactory2 = new JavaVideoFactory();
        VideoFactory videoFactory3 = new FEVideoFactory();
        Video video = videoFactory.getVideo();
        video.produce();
    }
}

⑥UML类图
6️⃣应用工厂方法的JDK类(java.util.collection)

①java.util.collection

public interface Collection extends Iterable {
    // Query Operations

    /**
     * Returns the number of elements in this collection.  If this collection
     * contains more than Integer.MAX_VALUE elements, returns
     * Integer.MAX_VALUE.
     *
     * @return the number of elements in this collection
     */
    int size();

    /**
     * Returns true if this collection contains no elements.
     *
     * @return true if this collection contains no elements
     */
    boolean isEmpty();

    /**
     * Returns true if this collection contains the specified element.
     * More formally, returns true if and only if this collection
     * contains at least one element e such that
     * (o==null ? e==null : o.equals(e)).
     *
     * @param o element whose presence in this collection is to be tested
     * @return true if this collection contains the specified
     *         element
     * @throws ClassCastException if the type of the specified element
     *         is incompatible with this collection
     *         (optional)
     * @throws NullPointerException if the specified element is null and this
     *         collection does not permit null elements
     *         (optional)
     */
    boolean contains(Object o);

    /**
     * Returns an iterator over the elements in this collection.  There are no
     * guarantees concerning the order in which the elements are returned
     * (unless this collection is an instance of some class that provides a
     * guarantee).
     *
     * @return an Iterator over the elements in this collection
     */
    Iterator iterator();
    ....
}

②ArrayList(由于源码太长,此处省略了大部分源码)

public class ArrayList extends AbstractList
        implements List, RandomAccess, Cloneable, java.io.Serializable
{
     /**
     * Returns an iterator over the elements in this list in proper sequence.
     *
     * 

The returned iterator is fail-fast. * * @return an iterator over the elements in this list in proper sequence */ public Iterator iterator() { return new Itr(); } /** * An optimized version of AbstractList.Itr */ private class Itr implements Iterator { int cursor; // index of next element to return int lastRet = -1; // index of last element returned; -1 if no such int expectedModCount = modCount; Itr() {} public boolean hasNext() { return cursor != size; } @SuppressWarnings("unchecked") public E next() { checkForComodification(); int i = cursor; if (i >= size) throw new NoSuchElementException(); Object[] elementData = ArrayList.this.elementData; if (i >= elementData.length) throw new ConcurrentModificationException(); cursor = i + 1; return (E) elementData[lastRet = i]; } public void remove() { if (lastRet < 0) throw new IllegalStateException(); checkForComodification(); try { ArrayList.this.remove(lastRet); cursor = lastRet; lastRet = -1; expectedModCount = modCount; } catch (IndexOutOfBoundsException ex) { throw new ConcurrentModificationException(); } } @Override @SuppressWarnings("unchecked") public void forEachRemaining(Consumer consumer) { Objects.requireNonNull(consumer); final int size = ArrayList.this.size; int i = cursor; if (i >= size) { return; } final Object[] elementData = ArrayList.this.elementData; if (i >= elementData.length) { throw new ConcurrentModificationException(); } while (i != size && modCount == expectedModCount) { consumer.accept((E) elementData[i++]); } // update once at end of iteration to reduce heap write traffic cursor = i; lastRet = i - 1; checkForComodification(); } final void checkForComodification() { if (modCount != expectedModCount) throw new ConcurrentModificationException(); } }

③UML类图

三 抽象工厂

1️⃣概念

定义:抽象工厂模式提供一个创建一系列相关或相互依赖对象的接口;
无需指定它们具体的类;
类型:创建型;

2️⃣适用场景

客户端(应用层)不依赖于产品类实例如何被创建 实现等细节;
强调一系列相关的产品对象(属于同一产品族)一起使用创建对象需要大量重复代码;
提供一个产品类的库,所有产品以同样的接口出现,从而使客户端不依赖于具体实现;

3️⃣优点

具体产品在应用层代码隔离,无须关心创建细节;
将一个系列的产品族统一到一起创建;

4️⃣缺点

规定了所有可能被创建的产品集合,产品族中扩展新的产品比较困难,需要修改抽象工厂的接口;
增加了系统的抽象性和理解难度;

5️⃣抽象工厂-产品等级结构与产品族
6️⃣抽象工厂Coding

①创建抽象工厂

public interface CourseFactory {
    Video getVideo();
    Article getArticle();
}

②创建具体工厂来实现抽象工厂

public class JavaCourseFactory implements CourseFactory {
    @Override
    public Video getVideo() {
        return new JavaVideo();
    }

    @Override
    public Article getArticle() {
        return new JavaArticle();
    }
}
public class PythonCourseFactory implements CourseFactory {
    @Override
    public Video getVideo() {
        return new PythonVideo();
    }

    @Override
    public Article getArticle() {
        return new PythonArticle();
    }
}

③创建抽象产品族

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

④创建具体产品

public class JavaArticle extends Article {
    @Override
    public void produce() {
        System.out.println("编写Java课程手记");
    }
}
public class JavaVideo extends Video {
    @Override
    public void produce() {
        System.out.println("录制Java课程视频");
    }
}
public class PythonArticle extends Article {
    @Override
    public void produce() {
        System.out.println("编写Python课程手记");
    }
}
public class PythonVideo extends Video {
    @Override
    public void produce() {
        System.out.println("录制Python课程视频");
    }
}

⑤创建测试类

public class Test {
    public static void main(String[] args) {
        CourseFactory courseFactory = new JavaCourseFactory();
        Video video = courseFactory.getVideo();
        Article article = courseFactory.getArticle();
        video.produce();
        article.produce();
    }
}

⑥UML类图
7️⃣抽象工厂的应用

①org.apache.ibatis.session

package org.apache.ibatis.session;

import java.sql.Connection;

/**
 * Creates an {@link SqlSession} out of a connection or a DataSource
 * 
 * @author Clinton Begin
 */
public interface SqlSessionFactory {

  SqlSession openSession();

  SqlSession openSession(boolean autoCommit);
  SqlSession openSession(Connection connection);
  SqlSession openSession(TransactionIsolationLevel level);

  SqlSession openSession(ExecutorType execType);
  SqlSession openSession(ExecutorType execType, boolean autoCommit);
  SqlSession openSession(ExecutorType execType, TransactionIsolationLevel level);
  SqlSession openSession(ExecutorType execType, Connection connection);

  Configuration getConfiguration();

}

②以SqlSession openSession(ExecutorType execType, TransactionIsolationLevel level)为例

③进入到DefaultSqlSessionFactory

@Override
  public SqlSession openSession(ExecutorType execType, TransactionIsolationLevel level) {
    return openSessionFromDataSource(execType, level, false);
  }

④打开openSessionFromDateSource

private SqlSession openSessionFromDataSource(ExecutorType execType, TransactionIsolationLevel level, boolean autoCommit) {
    Transaction tx = null;
    try {
      final Environment environment = configuration.getEnvironment();
      final TransactionFactory transactionFactory = getTransactionFactoryFromEnvironment(environment);
      tx = transactionFactory.newTransaction(environment.getDataSource(), level, autoCommit);
      final Executor executor = configuration.newExecutor(tx, execType);
      return new DefaultSqlSession(configuration, executor, autoCommit);
    } catch (Exception e) {
      closeTransaction(tx); // may have fetched a connection so lets call close()
      throw ExceptionFactory.wrapException("Error opening session.  Cause: " + e, e);
    } finally {
      ErrorContext.instance().reset();
    }
  }

⑤UML类图

你可能感兴趣的:(二 Java设计模式解析(工厂模式))