简介
工厂方法模式定义给一个:一个用于创建对象的接口,让子类决定实例化哪个类。
应用场景:比如有几个类,这几个类都有相似的功能,相似的属性,但又不完全相同,因此它们有一个共同的父亲。当需要使用这些个子类的时候,可以通过工厂方法模式产生这些个子类的对象,而不是用 new的方式去产生对象。
那么问题就又来了:通过new 的方式生成对象一句话就行,通过工厂方法模式产生对象虽然也不难,但是毕竟麻烦许多。那何必还要这种工厂模式呢?
工厂方法模式具有更好的封装性,说白了,工厂方法模式将创建对象的过程封装起来,需要对象是时就去工厂中提取,解耦。假设一种场景:
有一个类A,如果去new的话得这样:
A a = new A();
我在很多个地方使用到了A,我new了很多个,然后突然我要改A的名字了,现在要new A得这样:
B a = new B();
那我就比较麻烦了,我要把所有new A的地方都改掉。
使用工厂方法模式就比较简单了,我只需要修改创建A的那个工厂里面的代码就好了。
使用
1.给个图片先 :###
> 分析一下这个图片:
> 有一个抽象的工厂类Factory:是工厂类的基类;
> 还有一个抽象的产品类Product:是产品类的基类;
> 具体的产品类ConcreateProduct继承基类,实现方法;
> 具体的工厂类ConcreateProduct继承基类,实现创建产品类的功能;
2.代码走起来:
2.1.先看一下目录结构####
这里有两个包:
- factory:存放所有工厂类及其基类;
- product:存放所有产品类及其基类;
- 还有一个Activity:用来调用上面;
2.2.然后看一下xml布局####
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="st.zlei.com.factorypattern.MainActivity"
android:orientation="vertical">
<Button
android:id="@+id/a_button"
android:text="生产一个A衣服产品"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<Button
android:id="@+id/b_button"
android:text="生产一个B衣服产品"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<Button
android:id="@+id/a_reflect_button"
android:text="生产一个A衣服产品_反射"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<Button
android:id="@+id/b_reflect_button"
android:text="生产一个B衣服产品_反射"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</LinearLayout>
xml布局长这样:
功能就是点击一个按钮调用工厂类产生一个产品实例。
2.3.主要几个类####
//工厂的抽象类
//具体生产什么由子类去决定
public abstract class ClothesFactory {
//父类只有抽象的生产方法
//返回的也是产品的基类,不是具体的产品类
public abstract Clothes createClothes();
}
//产品的抽象类
public abstract class Clothes {
//这是产品应该具有的方法,但是具体内容是由具体产品来实现的
public abstract void method(Context context);
}
这里的产品指的是衣服
假设具体有2种衣服A和B
//A衣服产品
public class ClothesA extends Clothes {
@Override
public void method(Context context) {
Toast.makeText(context,"我是A衣服",Toast.LENGTH_LONG).show();
}
}
public class ClothesB extends Clothes {
@Override
public void method(Context context) {
Toast.makeText(context,"我是B衣服",Toast.LENGTH_LONG).show();
}
}
生产A,B产品的工厂
//A产品的工厂
public class ClothesAFactory extends ClothesFactory {
//返回的是A产品的实例
@Override
public Clothes createClothes() {
ClothesA clothesA = new ClothesA();
return clothesA;
}
}
//B产品的工厂
public class ClothesBFactory extends ClothesFactory {
//返回的是B产品实例
@Override
public Clothes createClothes() {
ClothesB clothesB = new ClothesB();
return clothesB;
}
}
使用这些工厂产生实例
a_button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//1.产生对应A产品的工厂
ClothesFactory factory = new ClothesAFactory();
//2.用工厂产生衣服A的对象
Clothes clothes = factory.createClothes();
//3.调用衣服A的方法
clothes.method(getApplicationContext());
}
});
b_button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//1.产生对应B产品的工厂
ClothesFactory factory = new ClothesBFactory();
//2.用工厂产生衣服B的对象
Clothes clothes = factory.createClothes();
//3.调用衣服B的方法
clothes.method(getApplicationContext());
}
});
2.4.运行结果####
可以看到功能正常
升级版本
上面使用的是为每一个产品定义一个工厂,也可以用反射的方式共用一个工厂。
需要修改一下factory父类了
//工厂的抽象类
public abstract class ClothesFactory_reflect {
//通过反射传进来一个T.class,返回一个T,
//T是Clothes的子类
//传入一个Class类决定哪一个产品类
public abstract <T extends Clothes>T createClothes(Class<T> clz) throws ClassNotFoundException, IllegalAccessException, InstantiationException;
}
具体的工厂类:
public class ClothesALLFactory extends ClothesFactory_reflect {
@Override
public <T extends Clothes> T createClothes(Class<T> clz) throws ClassNotFoundException, IllegalAccessException, InstantiationException {
//拿到产品的实例
Clothes clothes = (Clothes) Class.forName(clz.getName()).newInstance();
return (T) clothes;
}
}
调用:
a_reflect_button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
ClothesFactory_reflect clothesFactory_reflect = new ClothesALLFactory();
try {
//生产A产品就传入ClothesA.class
ClothesA clothes = clothesFactory_reflect.createClothes(ClothesA.class);
clothes.method(getApplicationContext());
} catch (Exception e) {
e.printStackTrace();
}
}
});
b_reflect_button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
ClothesFactory_reflect clothesFactory_reflect = new ClothesALLFactory();
try {
//生产B产品就传入ClothesB.class
ClothesB clothes = clothesFactory_reflect.createClothes(ClothesB.class);
clothes.method(getApplicationContext());
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
运行的结果和上面是一样的,就不贴图展示了.
总结
工厂模式多了一层封装,在工厂模式中,我们在创建对象时不会对客户端暴露创建逻辑,并且是通过使用一个共同的接口来指向新创建的对象。
但是使用会使得类结构变得复杂,在比较简单的情况下,比如产品类确定不会改变,并且我的需求也比较单一的情况下,我感觉完全没有必要使用这种模式.
本文中所使用的代码可以在本人GitHub上找到点这里