java设计模式-工厂模式
工厂模式:
- 工厂模式是java设计模式里最常用的设计模式之一。
- 工厂模式属于创建型模式,其提供了一种创建对象的最佳方法。
- 工厂模式在创建对象时不会对客户端暴露创建逻辑,是通过使用一个共同的接口来指向新的创建对象。
工厂模式相关介绍:
主要解决:主要解决接口选择的问题。
使用目的:定义创建对象的接口,让子类自己决定实例化哪一个工厂类,工厂模式使其创建的过程延迟到子类进行。
使用时间:不同条件下创建不同的实例。
解决方案:新增抽象工厂类,让抽象产品对应抽象工厂,让具体产品对应具体工厂,实际的创建工作推迟到子类工厂中去做。
工厂模式结构示意图:
![](https://img.haomeiwen.com/i9551898/5b0a44e687e33d40.png)
实例:
举例说明创建动物类其中包括猫和狗。
创建接口Animal,用于定义动物的特点特性
package 工厂模式.传统简单工厂模式;
/**
* @author : jimo
* desc: 宠物接口类
*/
public interface Animal {
/**种类介绍*/
void introduce();
/**爱吃的食物*/
void EatFood();
}
动物Animal的创建类工厂,AnimalFactory ,首先获取动物的对象,判断是什么动物(即猫或者狗),判断后实例化相应的对象类。例如:如果是猫,则创建猫的实例。
package 工厂模式.传统简单工厂模式;
public class AnimalFactory {
/**
* 获得宠物的对象
*
* @param animal dog:狗;cat:猫
* @return
*/
public Animal getAnimal(String animal){
if(animal.equals("cat")){
return new Cat();
}
else if(animal.equals("dog")){
return new Dog();
}
return null;
}
}
具体对象的实现
定义了 猫 ,对应接口为Animal
package 工厂模式.传统简单工厂模式;
public class Cat implements Animal{
@Override
public void introduce() {
System.out.println("我是一只猫咪,名字是小可!");
}
@Override
public void EatFood() {
System.out.println("小可最喜欢吃小鱼干了!");
}
}
具体对象的实现
定义了 狗 ,对应接口为Animal
package 工厂模式.传统简单工厂模式;
public class Dog implements Animal{
@Override
public void introduce() {
System.out.println("我是一只狗,我叫小黑!");
}
@Override
public void EatFood() {
System.out.println("小黑最喜欢吃骨头了!");
}
}
测试类:Test。
package 工厂模式.传统简单工厂模式;
public class Test {
public static void main(String[] args) {
AnimalFactory animalFactory=new AnimalFactory();
Cat cat= (Cat) animalFactory.getAnimal("cat");
Dog dog= (Dog) animalFactory.getAnimal("dog");
cat.introduce();
cat.EatFood();
dog.introduce();
dog.EatFood();
}
}
总结:
所谓的简单工厂模式就是建立一个工厂来创建新的对象。简单工厂模式又称为:静态工厂方法。
组成:
- 工厂类角色:核心部分,用于逻辑判断,创建相关产品对象。在上述例子中是:AnimalFactory。
- 抽象类产品对象:是具体的产品继承的父类或者实现的接口。在上述例子中是:Animal。
- 具体类产品对象:是工厂类创建的对象实例,是具体的对象。在上述例子中是cat和dog。
相关分析:
优点:
- 使用者想要创建一个对象的实例,只需要知道他的对象名即可。
- 扩展性高,如若想扩展产品对象只需要扩展一个工厂类。
- 隔绝产品对象的具体实现方法,只关心产品对象的接口。
缺点:
- 没新增扩展的时候都需要增加具体产品类和对象实现工厂,所以系统中的类会成倍添加。增加了系统的复杂度,同时也增加了具体产品类的依赖,依赖性太强对于程序不是一件好事。
- 扩展方法简单但是扩展的后果不好,即相对性。
- 对于开闭原则来说:开闭原则即对扩展开放,对修改封闭。
当主人又想养新的宠物的时候,需要创建新的宠物具体对象类,以及在宠物工厂创建新的判断,所以违背了开闭原则。对于新的宠物添加工厂类十分的被动。
在简单工厂模式的基础上,优化产生了工厂方法模式
工厂方法模式
因为简单工厂模式的缺点,其违背了开闭原则,扩展性较差。因为简单工厂模式的工厂类其内部有很多逻辑处理,如果新增对象就必须在工厂类里新建判断逻辑。
而工厂方法模式
优化了此问题解决方法。
package 工厂模式.工厂方法模式.宠物;
/**
* @author : jimo
* desc: 宠物接口类
*/
public interface Animals {
/**
* 介绍
*/
void introduce();
/**
* 爱吃的食物
* */
void EatFood();
}
动物工厂类接口
package 工厂模式.工厂方法模式.宠物;
public interface AnimalFactory {
Animals creatAnimal();
}
定义猫咪对象实体
package 工厂模式.工厂方法模式.宠物;
public class Cat implements Animals{
@Override
public void introduce() {
System.out.println("我是一只猫咪,名字是小可!");
}
@Override
public void EatFood() {
System.out.println("小可最喜欢吃小鱼干了!");
}
}
猫咪工厂
package 工厂模式.工厂方法模式.宠物;
public class CatFactory implements AnimalFactory{
@Override
public Animals creatAnimal() {
return new Cat();
}
}
main方法test类:
package 工厂模式.工厂方法模式.宠物;
public class test {
public static void main(String[] args) {
/**创建猫咪*/
AnimalFactory catFactory=new CatFactory();
Animals cat=catFactory.creatAnimal();
cat.introduce();
cat.EatFood();
/**创建小狗*/
AnimalFactory dogFactory=new DogFactory();
Animals dog=dogFactory.creatAnimal();
dog.introduce();
dog.EatFood();
}
}
可以看到,每个工厂只生产一种产品,客户端通过不同的工厂去生产不同的产品,而生产哪一产品的逻辑交给客户端这边去处理了。
抽象工厂模式:
抽象工厂模式是:围绕一个超级工厂创建其他工厂,该超级工厂又称为其他工厂的工厂。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。
而在DP中对于抽象工厂模式的定义:
抽象工厂模式(Abstract Factory),提供一个创建一系列相关或互相依赖对象的接口,而无需指定它们具体的类。
接口是负责创建一个相关对象的工厂,不需要显式指定它们的类。每个生成的工厂都能按照工厂模式提供对象。
意图:提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类。
主要解决:主要解决接口选择的问题。
何时使用:系统的产品有多于一个的产品族,而系统只消费其中某一族的产品。
使用场景: 1、QQ 换皮肤,一整套一起换。 2、生成不同操作系统的程序。
关键代码:在一个工厂里聚合多个同类产品。
![](https://img.haomeiwen.com/i9551898/e601f259565f8d38.jpg)
创建形状的接口
package 工厂模式.抽象工厂模式.抽象工厂.例2;
public interface Shape {
public void draw();
}
创建形状的具体实体:
圆形:
package 工厂模式.抽象工厂模式.抽象工厂.例2;
public class Circle implements Shape{
@Override
public void draw() {
System.out.println("画一个圆");
}
}
正方形:
package 工厂模式.抽象工厂模式.抽象工厂.例2;
public class Square implements Shape{
@Override
public void draw() {
System.out.println("画一个正方形");
}
}
创建颜色的接口:
package 工厂模式.抽象工厂模式.抽象工厂.例2;
public interface Color {
public void fill();
}
创建颜色接口的具体实现:
红色:
package 工厂模式.抽象工厂模式.抽象工厂.例2;
public class Rea implements Color{
@Override
public void fill() {
System.out.println("填满红色");
}
}
蓝色:
package 工厂模式.抽象工厂模式.抽象工厂.例2;
public class Blue implements Color{
@Override
public void fill() {
System.out.println("填满蓝色");
}
}
为两个接口创建一个抽象类来获取工厂:
package 工厂模式.抽象工厂模式.抽象工厂.例2;
public abstract class AbstractFactory {
public abstract Color getcolor(String color);
public abstract Shape getshape(String shape);
}
创建扩展了 AbstractFactory 的工厂类,基于给定的信息生成实体类的对象。
package 工厂模式.抽象工厂模式.抽象工厂.例2;
public class ShapeFactory extends AbstractFactory{
@Override
public Color getcolor(String color) {
return null;
}
@Override
public Shape getshape(String shape) {
if (shape==null){
return null;
}
else if(shape.equals("circle")){
return new Circle();
}
else if(shape.equals("square")){
return new Square();
}
return null;
}
}
package 工厂模式.抽象工厂模式.抽象工厂.例2;
public class ColorFactory extends AbstractFactory{
@Override
public Color getcolor(String color) {
if (color==null){
return null;
}
else if(color.equals("red")){
return new Rea();
}
else if(color.equals("blue")){
return new Blue();
}
return null;
}
@Override
public Shape getshape(String shape) {
return null;
}
}
创建一个工厂创造器/生成器类,通过传递形状或颜色信息来获取工厂。
package 工厂模式.抽象工厂模式.抽象工厂.例2;
public class FactoryProducer {
public static AbstractFactory getFactory(String choice){
if(choice.equalsIgnoreCase("shape")){
return new ShapeFactory();
}
if(choice.equalsIgnoreCase("color")){
return new ColorFactory();
}
return null;
}
}
使用 FactoryProducer 来获取 AbstractFactory,通过传递类型信息来获取实体类的对象。
package 工厂模式.抽象工厂模式.抽象工厂.例2;
public class test {
public static void main(String[] args) {
AbstractFactory shapeFactory=FactoryProducer.getFactory("shape");
Shape shape1=shapeFactory.getshape("circle");
shape1.draw();
Shape shape2=shapeFactory.getshape("square");
shape2.draw();
AbstractFactory colorFactory=FactoryProducer.getFactory("color");
Color color1=colorFactory.getcolor("red");
color1.fill();
Color color2=colorFactory.getcolor("blue");
color2.fill();
}
}
运行结果:
画一个圆
画一个正方形
填满红色
填满蓝色
分析:
优点:
抽象工厂模式最大的好处是易于交换产品系列,由于具体工厂类,例如 IFactory factory=new OracleFactory(); 在一个应用中只需要在初始化的时候出现一次,这就使得改变一个应用的具体工厂变得非常容易,它只需要改变具体工厂即可使用不同的产品配置。不管是任何人的设计都无法去完全防止需求的更改,或者项目的维护,那么我们的理想便是让改动变得最小、最容易,例如我现在要更改以上代码的数据库访问时,只需要更改具体的工厂即可。
抽象工厂模式的另一个好处就是它让具体的创建实例过程与客户端分离,客户端是通过它们的抽象接口操作实例,产品实现类的具体类名也被具体的工厂实现类分离,不会出现在客户端代码中。就像我们上面的例子,客户端只认识IUser和ILogin,至于它是MySQl里的表还是Oracle里的表就不知道了。
缺点:
但是任何的设计模式都有自身的缺陷都不是完美的,都有不适用的时候,例如抽象工厂模式虽然可以很方便的帮我们切换两个不同的数据库访问的代码。但是如果我们的需求来自于增加功能,例如我们还需要加多一个会员数据表 MemberData,那么我们就得先在以上代码的基础上,增加三个类:IMemberData,MysqlMemberData,OracleMemberData,还需要修改IFactory、MysqlFactory以及OracleFactory才可以完全实现。增加类还好说,毕竟我们是对扩展开放的,但是却要修改三个类,就有点糟糕了。
而且还有一个问题就是客户端程序类在实际的开发中,肯定不止一个,很多地方都会需要使用 IUser 或 ILogin ,而这样的设计,其实在每一个类的开始都需要写上 IFactory factory=new OracleFactory(); 这样的代码,如果我有一百个访问 User 或 Login 表的类,那不就得改一百个类?很多人都喜欢说编程是门艺术,但也的确如此,对于艺术我们应该去追求美感,所以这样大批量的代码更改,显然是非常丑陋的做法。
瑾墨
网友评论