简单工厂模式:一个抽象产品类,可以派生出多个具体产品类。一个具体工厂类,通过往此工厂的static方法中传入不同参数,产出不同的具体产品类实例。
工厂方法模式:一个抽象产品类,可以派生出多个具体产品类。一个抽象工厂类,可以派生出多个具体工厂类。每个具体工厂类只能创建一个具体产品类的实例。
抽象工厂模式: 多个抽象产品类,每个抽象产品类可以派生出多个具体产品类。 一个抽象工厂类,可以派生出多个具体工厂类。 每个具体工厂类可以创建多个具体产品类的实例。
总的来说就是在工厂中new 具体实现的子类-产品的具体实现。而对于用户,不关心他是怎么生成的,只需要关注工厂即可。所有的new 对象都在工厂。后面的去new工厂的时候调用理解成多态。
同时注意产品或工厂的方法抽象出来。
直接是实体工厂去new的设计模式叫简单工厂
有个工厂抽象类,并每个产品都有一个工厂去生产new 对象 叫工厂方法
一个用于创建对象的接口,让子类决定实例化哪一个类。
不需要生产一个产品就弄一个实体工厂。如果有新的东西过来,同样定义一个抽象工厂(和下面的对应,这是工厂方法),然后用之前的工程去new 出对象抽象工厂放抽象产品的接口或抽象对象,new回去才能调到产品那边
工厂方法和抽象工厂区别就是,工厂方法只生成一个产品,抽象工厂生成多个。简单点就是Factcty的那个接口或者类。加一个还是多个抽象产品类或接口,加多个就是抽象方法。加一个就是工厂方法
1.定义:在基类中定义创建对象的一个接口,让子类决定实例化哪个类。工厂方法让一个类的实例化延迟到子类中进行。
2.分类:
(1)简单工厂,又称静态工厂方法模式。
(2)工厂方法,又称多态性工厂模式。
(3)抽象工厂,又称工具箱模式。
3.为什么要使用工厂模式
(1)解耦:把对象的创建和使用过程分开。
(2)降低代码重复:如果创建某个对象的过程都很复杂,需要一定的代码量,而且很多地方都要用到,那么就会有很多的重复代码。
(3)降低维护成本:由于创建过程都由工厂统一管理,所以发生业务逻辑变化,不需要找到所有需要创建对象B的地方去逐个修正,只需要在工厂里修改即可,降低维护成本。
二、简单工厂模式
1.适用场景:
(1)需要创建的对象较少
(2)客户端不关心对象的创建过程
2.简单工厂模式的角色分配:
(1)工厂(Factory)角色 :简单工厂模式的核心,它负责实现创建所有实例的内部逻辑。工厂类可以被外界直接调用,创建所需的产品对象。
(2)抽象产品(Product)角色 :简单工厂模式所创建的所有对象的父类,它负责描述所有实例所共有的公共接口。
(3)具体产品(Concrete Product)角色:简单工厂模式的创建目标,所有创建的对象都是充当这个角色的某个具体类的实例
3.简单工厂实例
eg:创建一个可以绘制不同形状的绘图工具,可以绘制圆形,正方形,三角形,每个图形都会有一个draw()方法用于绘图。
(1)创建Shape接口
public interface Shape {
void draw();
}
(2)创建实现该接口的集体图形类
public class Circle implements Shape {
public Circle(){
System.out.println("Circle");
}
@Override
public void draw() {
System.out.println("Draw Circle");
}
}
public class Rectangle implements Shape {
public Rectangle(){
System.out.println("Rectangle");
}
@Override
public void draw() {
System.out.println("Draw Rectangle");
}
}
public class Square implements Shape {
public Square() {
System.out.println("Square");
}
@Override
public void draw() {
System.out.println("Draw Square");
}
}
(3)创建工厂类
public class ShapeFactory {
public static Shape createShape(String shapeType) { //注意是用的接口或者抽象类作为修饰对象!!!
if (shapeType == null) {
return null;
}
if (shapeType.equalsIgnoreCase("CIRCLE")) {
return new Circle();
} else if (shapeType.equalsIgnoreCase("RECTANGLE")) {
return new Rectangle();
} else if (shapeType.equalsIgnoreCase("SQUARE")) {
return new Square();
}
return null;
}
}
(4)测试
@Test
public void test() {
// 获取 Circle 的对象,并调用它的 draw 方法
Shape circle = ShapeFactory.createShape("CIRCLE");
circle.draw();
// 获取 Rectangle 的对象,并调用它的 draw 方法
Shape rectangle = ShapeFactory.createShape("RECTANGLE");
rectangle.draw();
// 获取 Square 的对象,并调用它的 draw 方法
Shape square = ShapeFactory.createShape("SQUARE");
square.draw();
}
结果:
Circle
Draw Circle
Rectangle
Draw Rectangle
Square
Draw Square
这样的实现有个问题,如果我们新增产品类的话,就需要修改工厂类中的getShape()方法,这很明显不符合 开放-封闭原则 。
4.使用反射机制改善简单工厂
public class ShapeFactory {
public static Object createShape(Class<? extends Shape> tClass) {
Object obj = null;
try {
obj = Class.forName(tClass.getName()).newInstance();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
return obj;
}
}
测试:
@Test
public void test() {
// 获取 Circle 的对象,并调用它的 draw 方法
Shape circle = (Shape) ShapeFactory.createShape(Circle.class);
circle.draw();
// 获取 Rectangle 的对象,并调用它的 draw 方法
Shape rectangle = (Shape) ShapeFactory.createShape(Rectangle.class);
rectangle.draw();
// 获取 Square 的对象,并调用它的 draw 方法
Shape square = (Shape) ShapeFactory.createShape(Square.class);
square.draw();
}
三、工厂方法模式
工厂方法模式是简单工厂的仅一步深化, 在工厂方法模式中,我们不再提供一个统一的工厂类来创建所有的对象,而是针对不同的对象提供不同的工厂。也就是说 每个对象都有一个与之对应的工厂 。
1.适用场景:
(1)一个类不知道它所需要的对象的类:在工厂方法模式中,客户端不需要知道具体产品类的类名,只需要知道所对应的工厂即可,具体的产品对象由具体工厂类创建;客户端需要知道创建具体产品的工厂类。
(2)一个类通过其子类来指定创建哪个对象:在工厂方法模式中,对于抽象工厂类只需要提供一个创建产品的接口,而由其子类来确定具体要创建的对象,利用面向对象的多态性和里氏
2.工厂方法角色分配:
(1)抽象工厂(Abstract Factory)角色:是工厂方法模式的核心,与应用程序无关。任何在模式中创建的对象的工厂类必须实现这个接口。
(2)具体工厂(Concrete Factory)角色 :这是实现抽象工厂接口的具体工厂类,包含与应用程序密切相关的逻辑,并且受到应用程序调用以创建某一种产品对象。
(3)抽象产品(AbstractProduct)角色 :工厂方法模式所创建的对象的超类型,也就是产品对象的共同父类或共同拥有的接口。
(4)具体产品(Concrete Product)角色 :这个角色实现了抽象产品角色所定义的接口。某具体产品有专门的具体工厂创建,它们之间往往一一对应
3.实例
(1)增加一个工厂接口:
public interface Factory {
public Shape getShape();
}
(2)增加相关工厂类:
圆形工厂类
public class CircleFactory implements Factory {
@Override
public Shape getShape() {
// TODO Auto-generated method stub
return new Circle();
}
}
长方形工厂类
public class RectangleFactory implements Factory{
@Override
public Shape getShape() {
// TODO Auto-generated method stub
return new Rectangle();
}
}
圆形工厂类
public class SquareFactory implements Factory{
@Override
public Shape getShape() {
// TODO Auto-generated method stub
return new Square();
}
}
(3)测试:
public class Test {
public static void main(String[] args) {
Factory circlefactory = new CircleFactory();
Shape circle = circlefactory.getShape();
circle.draw();
}
}
输出结果:
Circle
Draw Circle
四、抽象工厂模式
在工厂方法模式中,其实我们有一个潜在意识的意识。那就是我们生产的都是同一类产品。抽象工厂模式是工厂方法的仅一步深化,在这个模式中的工厂类不单单可以创建一种产品,而是可以创建一组产品。
1.适用场景
(1)和工厂方法一样客户端不需要知道它所创建的对象的类。
(2)需要一组对象共同完成某种功能时,并且可能存在多组对象完成不同功能的情况。(同属于同一个产品族的产品)
(3)系统结构稳定,不会频繁的增加对象。(因为一旦增加就需要修改原有代码,不符合开闭原则)
2.抽象工厂的角色分配
(1)抽象工厂(AbstractFactory)角色 :是工厂方法模式的核心,与应用程序无关。任何在模式中创建的对象的工厂类必须实现这个接口。
(2)具体工厂类(ConreteFactory)角色 :这是实现抽象工厂接口的具体工厂类,包含与应用程序密切相关的逻辑,并且受到应用程序调用以创建某一种产品对象。
(3)抽象产品(Abstract Product)角色 :工厂方法模式所创建的对象的超类型,也就是产品对象的共同父类或共同拥有的接口。
(4)具体产品(Concrete Product)角色 :抽象工厂模式所创建的任何产品对象都是某一个具体产品类的实例。在抽象工厂中创建的产品属于同一产品族,这不同于工厂模式中的工厂只创建单一产品。
3.抽象工厂与工厂方法有什么区别?
抽象工厂是生产一整套有产品的(至少要生产两个产品),这些产品必须相互是有关系或有依赖的,而工厂方法中的工厂是生产单一产品的工厂。
4.抽象工厂实例
不知道大家玩过穿越火线或者吃鸡这类游戏了吗,游戏中存在各种枪。我们假设现在存在AK、M4A1两类枪,每一种枪对应一种子弹。我们现在这样考虑生产AK的工厂可以顺便生产AK使用的子弹,生产M4A1的工厂可以顺便生产M4A1使用的子弹。(AK工厂生产AK系列产品包括子弹啊,AK枪的类型啊这些,M4A1工厂同理)
(1)创建相关接口:
枪
public interface Gun {
public void shooting();
}
子弹
public interface Bullet {
public void load();
}
(2)创建接口对应实现类:
AK类
public class AK implements Gun{
@Override
public void shooting() {
System.out.println("shooting with AK");
}
}
M4A1类
public class M4A1 implements Gun {
@Override
public void shooting() {
System.out.println("shooting with M4A1");
}
}
AK子弹类
public class AK_Bullet implements Bullet {
@Override
public void load() {
System.out.println("Load bullets with AK");
}
}
M4A1子弹类
public class M4A1
_Bullet implements Bullet {
@Override
public void load() {
System.out.println("Load bullets with M4A1");
}
}
(3)创建工厂接口
public interface Factory {
public Gun produceGun();
public Bullet produceBullet();
}
(4)创建具体工厂
生产AK和AK子弹的工厂
public class AK_Factory implements Factory{
@Override
public Gun produceGun() {
return new AK();
}
@Override
public Bullet produceBullet() {
return new AK_Bullet();
}
}
生产M4A1和M4A1子弹的工厂
public class M4A1_Factory implements Factory{
@Override
public Gun produceGun() {
return new M4A1();
}
@Override
public Bullet produceBullet() {
return new M4A1_Bullet();
}
}
(5)测试
public class Test {
public static void main(String[] args) {
Factory factory;
Gun gun;
Bullet bullet;
factory =new AK_Factory();
bullet=factory.produceBullet();
bullet.load();
gun=factory.produceGun();
gun.shooting();
}
}
输出结果:
Load bullets with AK
shooting with AK
下面这个例子更加明显:
//---------------------之前没变的代码区域---------------------//
//登陆接口(没变)也可以是抽象类
public interface ILogin {
void login();
}
//QQ登陆实现(没变)
public class QQLogin implements ILogin {
@Override
public void login() {
System.out.println("QQ登陆...");
}
}
//WeiXin登陆实现(没变)
public class WeiXinLogin implements ILogin {
@Override
public void login() {
System.out.println("微信登陆...");
}
}
//其他第三方登陆同上,省略...
//上面定义的支付接口(没变)也可以是抽象类
public interface IPay {
void pay();
}
//支付宝支付实现(没变)
public class AliPay implements IPay {
@Override
public void pay() {
System.out.println("支付宝支付...");
}
}
//微信支付实现(没变)
public class WeiXinPay implements IPay {
@Override
public void pay() {
System.out.println("微信支付...");
}
}
//其他支付同上,省略...
//---------------------之前没变的代码区域end---------------------//
//----------------工厂类和工厂接口换个角度设计(彻底改头换脸)----------------//
//工厂接口(之前只有登陆一种类型方法,现在从登陆和绑定支付2种类型考虑设计接口)也可以是抽象类
public interface IFactory { // public interface IFactory {
ILogin initQQLogin(); //======和之前对比》// ILogin initLogin(); 调用关系:多态 子类继承或者实现抽象类或者接口。所以给他new 父类= new 子类
父类型的应用可以指向子类型的对象
比如 Parent P = new Child();
都是产品的接口或抽象方法
抽象工厂就放产品的抽象类或接口
ILogin initWeiXinLogin(); // }
IPay bindAliPay();
IPay bindWeiXinPay();
}
//工厂实现类
public class FactoryImp implements IFactory{
@Override
public ILogin initQQLogin() {
return new QQLogin();
}
@Override
public ILogin initWeiXinLogin() {
return new WeiXinLogin();
}
@Override
public IPay bindAliPay() {
return new AliPay();
}
@Override
public IPay bindWeiXinPay() {
return new WeiXinPay();
}
}
//使用
FactoryImp factoryImp = new FactoryImp();
// 可以理解成 ILogin a = new factoryImp.initQQLogin()
ILogin a = new QQLogin()
a.login()父类引用指向子类的实现
factoryImp.initQQLogin().login();
factoryImp.initWeiXinLogin().login();
factoryImp.bindAliPay().pay();
factoryImp.bindWeiXinPay().pay();
如果还要增加工厂,相对于工厂方法来说,就不需要给每个产品去建立工厂了。直接用原有的工厂就能够生产出来。
//新加的新浪微博登陆
public class SinaLogin implements ILogin {
@Override
public void login() {
System.out.println("新浪微博登陆...");
}
}
//新加的银行支付
public class BankPay implements IPay {
@Override
public void pay() {
System.out.println("银行支付...");
}
}
//新加的接口(也可以是抽象类)
public interface INewFactory {
ILogin initSinaLogin();
IPay bindBankPay();
}
//新加的抽象工厂类,在原来基础上面新加的接口,搞定
public class NewFactoryImp implements IFactory,INewFactory{
@Override
public ILogin initQQLogin() {
return new QQLogin();
}
@Override
public ILogin initWeiXinLogin() {
return new WeiXinLogin();
}
@Override
public IPay bindAliPay() {
return new AliPay();
}
@Override
public IPay bindWeiXinPay() {
return new WeiXinPay();
}
@Override
public ILogin initSinaLogin() {
return new SinaLogin();
}
@Override
public IPay bindBankPay() {
return new BankPay();
}
}
//使用还是一样,省略...
————————————————
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
原文链接:https://blog.csdn.net/u014769864/article/details/78297248
作者:大漠孤烟直_v
链接:https://www.jianshu.com/p/37c7745877a0
来源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。