简单工厂模式属于类的创新型模式,又叫静态工厂方法模式,它可以根据参数的不同返回不同类的实例,被创建的实例通常都具有共同的父类。
Factory(工厂角色):工厂角色即工厂类,它是简单工厂模式的核心,负责实现创建所有产品实例的内部逻辑;工厂类可以被外界直接调用,创建所需的产品对象;在工厂类中提供了静态的工厂方法factoryMethod(),它的返回类型为抽象产品类型Product
Product(抽象产品角色):它是工厂类所创建的所有对象的父类,封装了各种产品对象的公有方法,它的引入将提高系统的灵活性,使得在工厂类中只需定义一个通用的工厂方法,因为所有创建的具体产品对象都是其子类对象。
ConcreteProduct(具体产品角色):它是简单工厂模式的创建目标,所有被创建的对象都充当这个角色的某个具体类的实例。每一个具体产品角色都继承了抽象产品角色,需要实现在抽象产品中声明的抽象方法
在简单工厂模式中,客户端通过工厂类来创建一个产品类的实例,而无须直接使用new关键字来创建对象,它是工厂模式家族中最简单的一员
简单工厂模式解决的问题是如何去实例化一个合适的对象。
简单工厂模式的核心思想就是:有一个专门的类来负责创建实例的过程。
具体来说,把产品看着是一系列的类的集合,这些类是由某个抽象类或者接口派生出来的一个对象树。而工厂类用来产生一个合适的对象来满足客户的要求。
如果简单工厂模式所涉及到的具体产品之间没有共同的逻辑,那么我们就可以使用接口来扮演抽象产品的角色;如果具体产品之间有功能的逻辑或,我们就必须把这些共同的东西提取出来,放在一个抽象类中,然后让具体产品继承抽象类。为实现更好复用的目的,共同的东西总是应该抽象出来的。
产品的抽象接口:
public abstract class food
{
//抽象类中存放的公共方法
public abstract void getFood();
}
建立具体的产品:
public class chicken extends food
{
@Override
public void getFood() {
System.out.println("鸡排");
}
}
public class fish extends food{
@Override
public void getFood() {
System.out.println("鱼排");
}
}
现在建立一个食物加工工厂:
public class FoodFactory
{
//将获取产品的方法设置为静态方法,那么就成了静态工厂模式
//方式1:
//传入一个字符串,判断是什么类型,然后返回相应的实例对象
public static food getFoodByString(String type) throws InstantiationException, IllegalAccessException {
if(type.equalsIgnoreCase("chicken"))
{
return chicken.class.newInstance();
}
else if(type.equalsIgnoreCase("fish"))
{
return fish.class.newInstance();
}
else
{
System.out.println("无法找到对应实例对象");
return null;
}
}
//方式2:
//传入一个字节码文件对象,通过反射来创建对象
public static food getFoodByFanshe(Class c)
{
food f=null;
try {
f= (food) Class.forName(c.getName()).newInstance();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
return f;
}
}
最后我们建立测试客户端:
//传入字符串
food chicken = FoodFactory.getFoodByString("chicken");
chicken.getFood();
//传入字节码文件对象
food fish = FoodFactory.getFoodByFanshe(fish.class);
fish.getFood();
工厂方法模式(Factory Method Pattern):定义一个用于创建对象的接口,让子类决定将哪一个类实例化。工厂方法模式让一个类的实例化延迟到其子类。
工厂方法模式又简称为工厂模式(Factory Pattern),又可称作虚拟构造器模式(Virtual Constructor Pattern)或多态工厂模式(Polymorphic Factory Pattern)。
工厂方法模式是一种类创建型模式。
与简单工厂模式相比,工厂方法模式最重要的区别是引入了抽象工厂角色,抽象工厂可以是接口,也可以是抽象类或者具体类
<!--引入注解工具类,扫描某个包下的注解-->
<dependency>
<groupId>org.reflections</groupId>
<artifactId>reflections</artifactId>
<version>0.9.11</version>
</dependency>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>21.0</version>
</dependency>
抽象产品:
public abstract class food
{
public abstract String getFood();
}
具体产品:
//自定义注解
@Food("chicken")
public class chicken extends food
{
@Override
public String getFood() {
return "肯德基";
}
}
@Food("fish")
public class chicken extends food
{
@Override
public String getFood() {
return "肯德基";
}
}
food注解:
//当前被描述的注解,会被保留到字节码文件中,并被JVM读取到
@Retention(RetentionPolicy.RUNTIME)
//value可以省略,只能作用在类上
@Target(ElementType.TYPE)
public @interface Food
{
//指定Bean在Map中的一个名字
//抽象方法
String value();
}
扫描food注解,放入一个Bean集合
//扫描com包下面标注了food注解的类,放入一个map集合中
public class BeanUtils
{
private Map<String,Object> InstanceObjects=new HashMap<>();
BeanUtils()
{
//扫描注解,放入Map集合中
Reflections f=new Reflections("com");
//获得所有标注了food注解的类
Set<Class<?>> classes = f.getTypesAnnotatedWith(Food.class);
//循环,生成一个实例,放入map集合中
classes.forEach(bean->
{
Object beanInstance=null;
try {
beanInstance=bean.newInstance();
//获得类上面标注的注解接口的实现对象
Food foodAnno = bean.getAnnotation(Food.class);
String beanName = foodAnno.value();
//放入Map集合中
InstanceObjects.put(beanName,beanInstance);
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
});
}
//获得指定Bean
public Object getBean(String beanName)
{
return InstanceObjects.get(beanName);
}
}
抽象工厂:
public abstract class factory
{
public abstract food getFood();
}
具体工厂:
public class fishFactory extends factory
{
BeanUtils beanUtils=new BeanUtils();
@Override
public food getFood()
{
fish f = (fish) beanUtils.getBean("fish");
return f;
}
}
public class chickenFactory extends factory
{
BeanUtils beanUtils=new BeanUtils();
@Override
public food getFood()
{
chicken f = (chicken) beanUtils.getBean("chicken");
return f;
}
}
测试:
public class test
{
@Test
public void test()
{
//获得鱼排
factory f=new fishFactory();
String food = f.getFood().getFood();
System.out.println(food);
//获得鸡排
f=new chickenFactory();
String food2 = f.getFood().getFood();
System.out.println(food2);
}
}
工厂方法模式是简单工厂模式的延伸,它继承了简单工厂模式的优点,同时还弥补了简单工厂模式的不足。工厂方法模式是使用频率最高的设计模式之一,是很多开源框架和API类库的核心模式。
抽象工厂模式(Abstract Factory Pattern):提供一个创建一系列相关或相互依赖对象的接口,而无须指定它们具体的类。抽象工厂模式又称为Kit模式,它是一种对象创建型模式。
在抽象工厂模式中,每一个具体工厂都提供了多个工厂方法用于产生多种不同类型的产品。
在工厂方法模式中具体工厂负责生产具体的产品,每一个具体工厂对应一种具体产品,工厂方法也具有唯一性,一般情况下,一个具体工厂中只有一个工厂方法或者一组重载的工厂方法。但是有时候我们需要一个工厂可以提供多个产品对象,而不是单一的产品对象。
当系统所提供的工厂所需生产的具体产品并不是一个简单的对象,而是多个位于不同产品等级结构中属于不同类型的具体产品时需要使用抽象工厂模式。
抽象工厂模式是所有形式的工厂模式中最为抽象和最具一般性的一种形态。
抽象工厂模式与工厂方法模式最大的区别在于,工厂方法模式针对的是一个产品等级结构,而抽象工厂模式则需要面对多个产品等级结构,一个工厂等级结构可以负责多个不同产品等级结构中的产品对象的创建 。当一个工厂等级结构可以创建出分属于不同产品等级结构的一个产品族中的所有对象时,抽象工厂模式比工厂方法模式更为简单、有效率。
产品族:一个品牌下面的所有产品;例如华为下面的手机,路由器,电脑 称为华为的产品族;
产品等级:多个品牌下面的同种产品;例如华为和小米下面的手机称为一个产品等级;
1 public abstract class AbstractFactory
2 {
3 public abstract AbstractProductA createProductA();
4 public abstract AbstractProductB createProductB();
5 }
1 public class ConcreteFactory1 extends AbstractFactory
2 {
3 public AbstractProductA createProductA()
4 {
5 return new ConcreteProductA1();
6 }
7 public AbstractProductB createProductB()
8 {
9 return new ConcreteProductB1();
10 }
11 }
在抽象工厂中声明了多个工厂方法,用于创建不同类型的产品,抽象工厂可以是接口,也可以是抽象类或者具体类
具体工厂实现了抽象工厂,每一个具体的工厂方法可以返回一个特定的产品对象,而同一个具体工厂所创建的产品对象构成了一个产品族
以下图为例,有手机和路由器两种产品,有华为和小米两种品牌,两种品牌都可以生产手机和路由器;
1.手机产品接口和路由器产品接口-----抽象产品层
//手机产品接口
public interface IPhoneProduct {
//开机
void start();
//关机
void shutdown();
//打电话
void callup();
//发邮件
void sendSMS();
}
//路由器产品接口
public interface IRouterProduct {
//开机
void start();
//关机
void shutdown();
//打开wifi
void openwifi();
//设置
void setting();
}
2.华为和小米的产品的4个实现类----具体产品的实现类
//华为手机实现类
public class HuaweiPhone implements IPhoneProduct {
@Override
public void start() {
System.out.println("开启华为手机");
}
@Override
public void shutdown() {
System.out.println("关闭华为手机");
}
@Override
public void callup() {
System.out.println("华为手机打电话");
}
@Override
public void sendSMS() {
System.out.println("华为手机发邮件");
}
}
//华为路由器实现类
public class HuaweiRouter implements IRouterProduct {
@Override
public void start() {
System.out.println("开启华为路由器");
}
@Override
public void shutdown() {
System.out.println("关闭华为路由器");
}
@Override
public void openwifi() {
System.out.println("打开华为wifi");
}
@Override
public void setting() {
System.out.println("设置华为路由器");
}
}
//小米手机实现类
public class XiaomiPhone implements IPhoneProduct {
@Override
public void start() {
System.out.println("开启小米手机");
}
@Override
public void shutdown() {
System.out.println("关闭小米手机");
}
@Override
public void callup() {
System.out.println("小米手机打电话");
}
@Override
public void sendSMS() {
System.out.println("小米手机发邮件");
}
}
//小米路由器实现类
public class XiaomiRouter implements IRouterProduct {
@Override
public void start() {
System.out.println("开启小米路由器");
}
@Override
public void shutdown() {
System.out.println("关闭小米路由器");
}
@Override
public void openwifi() {
System.out.println("打开小米wifi");
}
@Override
public void setting() {
System.out.println("设置小米路由器");
}
}
3.工厂接口类----抽象工厂
//产品工厂接口
public interface IProductFactory {
//生产手机
IPhoneProduct phoneProduct();
//生成路由器
IRouterProduct routerProduct();
}
4.华为和小米工厂实现类,继承工厂接口----具体工厂
//华为工厂实现类
public class HuaweiFactory implements IProductFactory {
@Override
public IPhoneProduct phoneProduct() {
return new HuaweiPhone();
}
@Override
public IRouterProduct routerProduct() {
return new HuaweiRouter();
}
}
//小米工厂实现类
public class XiaomiFactory implements IProductFactory {
@Override
public IPhoneProduct phoneProduct() {
return new XiaomiPhone();
}
@Override
public IRouterProduct routerProduct() {
return new XiaomiRouter();
}
}
5.客户端,通过 IProductFactory 创建各自的工厂,通过工厂拿到对应的产品
public class Client {
public static void main(String[] args) {
System.out.println("============小米产品============");
//创建小米工厂
IProductFactory xiaomiFactory = new XiaomiFactory();
//生产小米手机
IPhoneProduct xiaomiPhone = xiaomiFactory.phoneProduct();
xiaomiPhone.start();
xiaomiPhone.sendSMS();
//生产小米路由器
IRouterProduct xiaomiRouter = xiaomiFactory.routerProduct();
xiaomiRouter.openwifi();
xiaomiRouter.setting();
System.out.println("============华为产品============");
//创建华为工厂
IProductFactory huaweiFactory = new HuaweiFactory();
//生产华为手机
IPhoneProduct huaweiPhone = huaweiFactory.phoneProduct();
huaweiPhone.start();
huaweiPhone.sendSMS();
//生产华为路由器
IRouterProduct huaweiRouter = huaweiFactory.routerProduct();
huaweiRouter.openwifi();
huaweiRouter.setting();
}
}
抽象工厂模式的主要优点如下:
抽象工厂模式的主要缺点如下:
拓展一个产品等级结构,生产一个新的产品:
我们会发现,拓展一个产品族是非常困难的,例如产品族中新增一个笔记本电脑,也就是说华为和小米现在可以生产电脑了,如下图所示(黄色字体为新增一个产品族需要做的事),对顶层的工厂接口类也要修改,这是非常麻烦的;
拓展一个产品等级,新增加一个工厂,生产所有现有的产品:
如果扩展一个产品族,例如新增一个手机,也就是说新增一个品牌来生产手机,如下图所示(黄色字体为新增一个产品等级需要做的事),新增一个产品等级不用修改原来的代码,符合OCP原则,这是非常舒服的;
“开闭原则”要求系统对扩展开放,对修改封闭,通过扩展达到增强其功能的目的。对于涉及到多个产品族与多个产品等级结构的系统,其功能增强包括两方面: