摘要:
你是否明白什么是工厂模式,什么时候使用工厂模式,使用工厂模式包含哪几种方式?这篇文章将带你深入理解工厂(Factory)模式,文章以线程池创建线程为例子,线程池以缓存线程池,即Executors.newCachedThreadPool()
为代表,一个APP项目中可能需要多个线程,多则几十个,如果使用new
逐一创建,会显得有点繁琐、麻烦,这个时候可以考虑工厂模式。
一、工厂模式应用于线程池实例
在Android多线程开发中,线程池在TeachCourse的印象中包含四个方面:1.执行器,2.工作任务,3.线程池,4.线程,它们之间的关系是:执行器从线程池已有的线程中取出一条线程执行已提交的工作任务,它们的UML类图如下:
该实例涉及到的类包括:Executor
、Executors
、Runnable
、ThreadFactory
、Thread
等,Executor
是一个接口,还包含其实现类及其子类,Executors
是对Executor
及其子类的封装,Runnable
表示需要执行的工作任务,ThreadFactory
表示创建线程的工厂,Thread
表示线程,具体的用法如下:
public class DefaultConfigurationFactory {
/**创建执行器对象*/
public static Executor createTaskDistributor() {
return Executors.newCachedThreadPool(createThreadFactory(Thread.NORM_PRIORITY, "uil-pool-d-"));
}
/**创建线程工厂对象*/
private static ThreadFactory createThreadFactory(int threadPriority, String threadNamePrefix) {
return new DefaultConfigurationFactory.DefaultThreadFactory(threadPriority, threadNamePrefix);
}
/**重写线程工厂*/
private static class DefaultThreadFactory implements ThreadFactory {
private static final AtomicInteger poolNumber = new AtomicInteger(1);
private final ThreadGroup group;
private final AtomicInteger threadNumber = new AtomicInteger(1);
private final String namePrefix;
private final int threadPriority;
DefaultThreadFactory(int threadPriority, String threadNamePrefix) {
this.threadPriority = threadPriority;
SecurityManager s = System.getSecurityManager();
group = (s != null) ? s.getThreadGroup() : Thread.currentThread().getThreadGroup();
namePrefix = threadNamePrefix + poolNumber.getAndIncrement() + "-thread-";
}
@Override
public Thread newThread(Runnable r) {
Thread t = new Thread(group, r, namePrefix + threadNumber.getAndIncrement(), 0);
if (t.isDaemon()) t.setDaemon(false);
t.setPriority(threadPriority);
return t;
}
}
}
在上面的代码中,有两个地方使用到工厂模式,第一个地方是调用newThread()
返回Thread对象,第二个地方是调用createThreadFactory()
返回ThreadFactory对象,接下来我们可以使用创建的执行器Executor
执行提交的工作任务Runnable
,具体的用法如下:
DefaultConfigurationFactory.createTaskDistributor().execute(new LoadTask(textView,handler));
在一个APP项目中会出现多个工作任务,使用线程池后不要担心创建线程的问题,只需要将工作任务按照上述的方法提交给Executor
执行器即可,比如:TeachCourse创建一个加载和显示图片的工作任务LoadAndDisplayImageTask
,在需要的地方,执行如下代码:
DefaultConfigurationFactory.createTaskDistributor().execute(new LoadAndDisplayImageTask(imageView,handler));
到这里,我们学习了工厂模式在线程池中的使用,通过线程池减少线程对象创建、销毁的开销,工厂模式的一个特点:将创建相同对象的过程封装成方法,调用同一个方法完成相同对象的创建。
二、什么是工厂模式?
通过工厂模式应用于线程池的例子的学习,首先让读者对工厂模式有一个大概的认识,对上面的例子不是很理解,不影响你对后面工厂模式的学习,毕竟工厂模式应用于线程池的例子涉及的知识点包括多线程、消息队列,这些知识在本篇文章中不做过多介绍,需要读者具备一定的基础,而本篇文章重点学习工厂模式。
工厂模式的特点:将创建相同对象的过程封装成方法,调用同一个方法完成相同对象的创建。
现实中的工厂,负责生产厂品,工厂模式的工厂负责创建对象,创建一个对象会为对象分配一块独立的内存,创建对象的过程就是不断分配内存的过程。生活的农村TeachCourse对工厂印象深刻,以前村里没有工厂生产棉衣,家里人会买一些毛衣的回来,家人更多时候手工织毛衣,织一件毛衣可能需要有两个月甚至更长,大部分是满足家庭所需;但过了有段时间后,一些领导干部决定带动村里经济发展,着手发展一些第三产业,开始招商引资,吸引了商家创建在村周边创办了一些工厂,让工厂负责生产日常所需的毛衣,同时将多余的产品销售全国各地,原本有两个月完成一件的毛衣,现在可以一天生产几十、几百甚至上千。从这个例子体现出工厂的高效率。
手动生产毛衣的过程,如下图:
在面向对象的编程语言中,将织毛衣转化成Sweater
类,代码如下:
public class Sweater {
private String size;
private String style;
private String material;
public Sweater(String size, String style, String material) {
this.size = size;
this.style = style;
this.material = material;
}
public void makeSweater() {
System.out.println("当前生产的毛衣:");
System.out.println("尺寸:" + size);
System.out.println("样式:" + style);
System.out.println("材料:" + material);
}
}
工厂生产毛衣的过程,准备好毛衣的尺寸、材料、样式等基本信息,制作成一份模板,然后开始批量生产,所以工厂生产出来某批量的毛衣在尺寸、材料和样式上没有很大的差异。
工厂生产毛衣的过程,如下图:
将毛衣工厂转化成SweaterFactory
类,类里面包含对应的属性、方法,代码如下:
public class SweaterFactory {
public static Sweater createSweater(String size,String style,String material){
return new Sweater(size,style,material);
}
}
总结:工厂模式是将创建相同对象的过程封装成方法,调用同一个方法完成相同对象的创建。
三、 什么时候使用工厂模式?
如果你想要生产相同尺寸、样式和材料没有差异的一批毛衣,就应该考虑通过工厂进行生产;如果你只想织一两件日常所需的毛衣,暂时就不用考虑工厂模式。在上面线程池的例子中,因为考虑线程池可能不止一两条线程,所以考虑通过线程工厂负责创建线程,可以满足线程池需要多少创建多少的要求。
总结:在考虑创建一批没有很大差异性的对象时,可以考虑使用工厂模式
四、工厂模式的几种方式
我们生产的毛衣款式按年龄段划分可以有:童装、成人装、老年装;不同年龄段有分为男装、女装,按照上面所述代码,每次创建对象都需要输入:毛衣的尺寸、样式和材质,能不能将每一种款式封装成一份模板,每次只需要定义调用createSweater()
方法,而不用关心传入的参数呢?
开始对上面的代码,进行重构,首先声明一个产品的接口Product
,代码如下:
public interface Product {
void makeSweater();
}
根据毛衣款式的不同,分别实行Product
接口,童装具体类,代码如下:
public class ChildrenSweater implements Product {
@Override
public void makeSweater() {
System.out.println("当前生产的毛衣:");
System.out.println("尺寸:" + "童装大小");
System.out.println("样式:" + "松绿色");
System.out.println("材料:" + "纯棉体恤");
}
}
成人装具体类,代码如下:
public class AdultSweater implements Product {
@Override
public void makeSweater() {
System.out.println("当前生产的毛衣:");
System.out.println("尺寸:" + "成人大小");
System.out.println("样式:" + "夏装男士圆领净色纯色短T男装");
System.out.println("材料:" + "纯棉体恤");
}
}
老年装具体类,代码如下:
public class OldSweater implements Product {
@Override
public void makeSweater() {
System.out.println("当前生产的毛衣:");
System.out.println("尺寸:" + "老人大小");
System.out.println("样式:" + "中老年男装夹克2017春季新款");
System.out.println("材料:" + "锦纶");
}
}
第一种方式:
工厂不能像上面一样只负责生产一种款式的毛衣,现在要根据生产的需求,工厂要能批量生产童装、成人装和老年装的产品,开始对SweaterFactory
进行重构,代码如下:
public class SweaterFactory {
public static <T extends Product> T createProduct(Class<T> clz){
Product product=null;
try {
product=(Product) Class.forName(clz.getName()).newInstance();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
return (T) product;
}
}
接下来工厂就可以批量生产不同款式的毛衣,代码如下:
/**批量生产童装*/
Product product=SweaterFactory.createProduct(ChildrenSweater.class);
product.makeSweater();
/**批量生产成人装*/
product=SweaterFactory.createProduct(AdultSweater.class);
product.makeSweater();
/**批量生产老年装*/
product=SweaterFactory.createProduct(OldSweater.class);
product.makeSweater();
这是一种动态批量生产对象的方式,需要哪一个类的对象传入那一个类,然后调用相同的makeSweater()
方法,特点:使用反射知识,理解比较困难,但代码简洁
第二种方式:
不使用反射的知识,通过类型识别生产哪一款毛衣,创建对应毛衣对象,特点:简单明了,依赖性强,代码如下:
public class SweaterFactory {
public static Product createProduct(String type) {
Product product
switch (type) {
case "children":
product = new ChildrenSweater();
break;
case "adult":
product = new AdultSweater();
break;
case "old":
product = new OldSweater();
break;
default:
product = new ChildrenSweater();
break;
}
return product;
}
}
第三种方式:
根据程序的单一职责,一个工厂负责生产一种款式的毛衣,ChildrenFactory
负责生产童装,AdultFactory
负责生产成人装,OldFactory
负责生产老年装,然后再进行细分,童装还可以划分成不同年龄段的男孩、女孩款式,成人装进一步划分高矮胖瘦的男人、女人款式,老年装划分不同年龄身高的男款、女款,多个工厂的特点:职责单一,方便扩展
重构SweaterFactory
为抽象工厂,代码如下:
public abstract class SweaterFactory {
public abstract Product createProduct();
}
负责生产童装的工厂,代码如下:
public class ChildrenFactory extends SweaterFactory {
@Override
public Product createProduct() {
return new ChildrenSweater();
}
}
负责生产成人装的工厂,代码如下:
public class AdultFactory extends SweaterFactory {
@Override
public Product createProduct() {
return new AdultSweater();
}
}
负责生产老年装的工厂,代码如下:
public class OldFactory extends SweaterFactory {
@Override
public Product createProduct() {
return new OldSweater();
}
}
第三种方式又叫做抽象工厂模式,属于一种特殊的工厂模式,同时复合工厂模式的特点,工厂模式的特点:将创建相同对象的过程封装成方法,调用同一个方法完成相同对象的创建
在实际的开发中,把握住了工厂模式的特点,然后进行重构,还会有其他的方式,创建相同对象的过程可以封装成实例方法或类方法,都是可以的,文章开头线程池的实例中就包含实例方法和类方法。
五、总结
本篇文章从什么是工厂模式、什么时候使用工厂模式以及工厂模式几种方式入手,认真分析了工厂模式的特点:将创建相同对象的过程封装成方法,调用同一个方法完成相同对象的创建,把符合该特点的设计模式称为工厂模式,最后列举几种工厂模式的方式,深入理解工厂模式。
你可能感兴趣的文章
转载请注明出处: https://www.teachcourse.cn/2459.html ,谢谢支持!