设计模式认识和自己的理解------简单工厂模式、工厂模式、抽象工厂模式

引言

设计模式多且复杂,而且相信很多小伙伴在学习完之后,也没法得到及时的使用,也不知道使用场景,导致学过的设计模式很快就忘记了。今天,我就以比较通俗易懂的方式,勾起大家的回忆。

如有不足之处,还请多多包涵
如有好的思想,希望多多在评论区分享,比如可以说说自己认为哪些地方可以用到本文中的

简单工厂模式

我们现在要写多个类,而这多个类又恰有相同的方法,那我们就可以将这个相同的方法给写成一个接口,而这个接口就是暴露给我们使用者看到的东西。即我们知道去用这个接口能得到什么。至于具体得到什么,则由系统内部根据你的要求而自动分配给你。

比如你想要对一串数据进行排序

现在有一个接口,这个接口的方法就是排序。

现在有三个类实现了这个排序接口。

第一个类实现的排序方法是冒泡排序

第二个类实现的排序方法是快速排序

第三个类实现的排序方法是插入排序

好,问题来了,那我们使用接口方法后是怎么找到我们想要的排序算法呢?
就是通过我们说的这个工厂类。

   简单工厂里面则包含预先写好的映射关系。
   
   因为我们如果真的想要用到类里的方法那我们肯定就是要先实例化这个类
   
   比如我希望通过拼音(即所说的参数)去找到对应类所拥有的的排序方法
  
   那就是要通过这个参数,拿到对应类的实例化对象吧

这边聊一下简单工厂中为啥要用static方法,原因就是方便调用,静态的方法可以直接使用类名调用,而不用进行实例化调用。所以简单工厂模式又被称为静态工厂方法。

所以我们流程就是用接口通过设置好的对应的参数去得到具体的实例,然后调用方法即可。

聊聊优点吧
很明显,避免我们使用者直接实例化具体对象的类,而将这种行为交给工厂类去实现,我们只需要告诉工厂我们要的是什么。
就好比我跟海鲜工厂说我要一条鱼,海鲜工厂立马准备一条新鲜的鱼给我送过来,而不是我得自己先有一个鱼塘,从自己的鱼塘里捞!
降低了使用者的责任、工作。
聊聊缺点吧
但是吧,搞得工厂很麻烦。如果我想要吃鱼翅,海鲜工厂里没有,那海鲜工厂为了满足顾客的需求,就得获取鱼翅。
说白一点,就是 不满足“开闭原则” 了,毕竟好的类在写出来之后,都应该是扩展的,而不是修改自身去满足别人。

举个例子吧,就好比海鲜工厂没有鱼翅,但他可以去和有鱼翅的海鲜工厂商量,让他给自己提供鱼翅,等到用户不需要鱼翅的时候,再取消进购。这样就不会对本身的工厂产生担心用户以后是否购买鱼翅的风险,而只是需要去沟通一下就行了。而我们的类与类之间,实际就是“沟通”呗

工厂模式

既然简单工厂模式破坏了开闭原则,那工厂模式就是对这个地方做的一个改进。就是让每一个类都拥有一个对应的产品类。

举个例子吧,
我们现在有三个类

第一个类是手机
第二个类是笔记本电脑
第三个类是手表

那么显然我们也有对应的三个工厂

第一个工厂是手机工厂
第二个工厂是电脑工厂
第三个工厂是手表工厂

接下来就是找出相同的地方做成一个接口,然后让这三个类实现这个接口

那么假设有一个接口product,里面有一个方法叫做 ,showProduct()

三个工厂都有一个 createProduct()方法,创造产品!

那么假设有一个接口bigFactory,里面有一个方法叫做,createProduct() ,这个方法的类型就应该是 product 
(这样我们子工厂实现createProduct方法后进行实例化,可以向下转型,获取具体的子类) 

那在我们的使用时,我们只需要为这么多的工厂添加一个管理者

让这个管理者和客户端交流,然后管理者去告诉具体哪一个工厂做一个产品出来,给我们的客户端

package csdnFactoryModel;

import csdnFactoryModel.Factory.BigFactory;
import csdnFactoryModel.Product.Product;

public class FactoryManagement {
    public static Product tellWhichFactoryToCreateProduct(String name) throws ClassNotFoundException, IllegalAccessException, InstantiationException {
        BigFactory concreteFactory = null;
        String PackageName  = BigFactory.class.getPackage().getName();
        StringBuffer sb = new StringBuffer();
        sb.append(PackageName);
        sb.append(".");
        sb.append(name);
        concreteFactory  = (BigFactory) Class.forName(sb.toString()).newInstance();
        return concreteFactory.createProduct();
    }
}

通过bigFactory去反射得到具体的子工厂
然后具体的子工厂使用createProduct方法得到具体的产品类,返回给客户端
这样客户端就能拿到产品后调用产品类的方法showProduct
就能拿到结果

看看客户端代码
先看一下我的目录结构,
在这里插入图片描述
上面的管理者里面的代码就是,通过FactoryManagement 去找到存工厂的包名,然后利用反射找到具体的工厂类,工厂类里面可以返回一个产品实例。
下面是客户端代码,直接可以用static修饰的类的方法

public class Cilent {
    public static void main(String[] args) throws ClassNotFoundException {
        String []strs = {"phoneFactory","computerFactory","watchFactory"};
        for(String str : strs){
            try {
                FactoryManagement.tellWhichFactoryToCreateProduct(str).showProduct();
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            } catch (InstantiationException e) {
                e.printStackTrace();
            }
        }
    }
}

聊聊优点吧
很明显,我们不需要再去修改已经写好的工厂类,而只需要拓展实现接口的子类即可。
聊聊缺点吧
也很明显,加一个,就得写一个,代码开发量增大

抽象工厂模式

抽象工厂,我找了一张图片,帮助大家理解
在这里插入图片描述
我来谈谈我对上图的理解。
跟工厂模式相比,一个产品由一个工厂生产,多个产品就出现了多个工厂,你想想要是在现实生活中,那实在是显得很麻烦。
一般来看,一个工厂可以生产多个产品。再往大了点,一个工厂应该可以生产多个系列的产品,而一个系列的产品,又可以有多个具体的产品。所以在一个大工厂内部,其实我们可以划分出多个不同的子工厂,而每一个子工厂就是对应着一个系列的产品,我们能够通过这个子工厂拿到最具体的产品。

举个实例

苹果公司(最大的统称)
内部分为 手机工厂,电脑工厂
手机工厂里面生产     苹果7  苹果8  苹果X
电脑工厂里面生产     MacBookA   MacBookB  MacBookC     (懂就行)

具体的内部工厂通过系列产品的接口,能返回具体的产品,这里跟上面的工厂模式有点像的,只是上面是去找工厂,一个工厂只会返回一个产品。而当我们有多个工厂多个产品时,这个时候,我们就要既能找工厂又要能找产品。

而至于最上方各个工厂继承的这个抽象工厂类,因为这边用到的是继承,所以这个类一定是一个抽象类,定义抽象的方法,交给子类去实现。而由于这边我是通过反射机制去取到类名的,所以我们的子类一定要实现抽象父类的全部方法,否则是没法进行实例化的。因为我们知道没实现抽象父类全部方法的子类一定是一个抽象子类,而抽象类是没法进行实例化的。所以在用Class.forName().nexInstance时就会报错。
(不用抽象类,用接口也是可以实现的)

我们得写一个内部管理者,去管理这个公司, 有人来跟公司谈业务了(告诉要哪个系列的哪个手机或者电脑),就由这个管理者去找具体的工厂。

然后建议先动手按照图片的逻辑和之前写工厂模式的基础先敲一下代码,敲出来之后,再来对照我写的代码吧

下面是上面图片的具体实现代码部分和我的项目结构

这边不粘,具体产品的代码了


public interface Shape {
//      展示自己是什么形状的方法
      public void show();
}

public interface Color {
    //我想要添加的颜色是。。。
    public void addColor();
}



//抽象工厂
public abstract class AbstractFactory {
    public abstract Shape getShape(String name) throws ClassNotFoundException, IllegalAccessException, InstantiationException;
    public abstract Color getColor(String name) throws ClassNotFoundException, IllegalAccessException, InstantiationException;
}

//具体工厂
public  class ColorFactory extends AbstractFactory {
    @Override
    public Shape getShape(String name) throws ClassNotFoundException, IllegalAccessException, InstantiationException {
        return null;
    }

    @Override
        public Color getColor(String name) throws ClassNotFoundException, IllegalAccessException, InstantiationException {
            Color color = null;
            String PackageName  = Color.class.getPackage().getName();
            StringBuffer sb = new StringBuffer();
            sb.append(PackageName);
            sb.append(".");
            sb.append(name);
            color = (Color) Class.forName(sb.toString()).newInstance();
            return color;
        }

}


public class ShapeFactory extends AbstractFactory {
    @Override
    public Shape getShape(String name) throws ClassNotFoundException, IllegalAccessException, InstantiationException {
        Shape shape = null;
        String PackageName  =Shape.class.getPackage().getName();
        StringBuffer sb = new StringBuffer();
        sb.append(PackageName);
        sb.append(".");
        sb.append(name);
        shape = (Shape) Class.forName(sb.toString()).newInstance();
        return shape;
    }

    @Override
    public Color getColor(String name) throws ClassNotFoundException, IllegalAccessException, InstantiationException {
        return null;
    }
}


/**
* 与客户交流的管理者
*/

public class FactoryProducer  {
    public static AbstractFactory findFactory(String name) throws ClassNotFoundException, IllegalAccessException, InstantiationException {
        AbstractFactory factory = null;
        String PackageName = AbstractFactory.class.getPackage().getName();
        StringBuffer sb = new StringBuffer();
        sb.append(PackageName);
        sb.append(".");        
        sb.append(name);
        factory = (AbstractFactory) Class.forName(sb.toString()).newInstance();
        return factory;
    }
}


/**
* 客户端
*/
public class Client {
    public static void main(String[] args) throws IllegalAccessException, InstantiationException, ClassNotFoundException {
        String []factories = {"ColorFactory","ShapeFactory"};
        String []colors = {"Red","Blue","Green"};
        String []shapes = {"Circle","Rectangle","Square"};
        for(String factory:factories){
            AbstractFactory af = FactoryProducer.findFactory(factory);
            for(String color :colors){
                if(af.getColor(color)!=null) {    //这边得判空,因为按我的写法,父类方法全部实现,也会全部遍历一遍数组,所以会返回空的情况
                    af.getColor(color).addColor();
                }
            }
            for (String shape:shapes){
                if(af.getShape(shape)!=null) {
                    af.getShape(shape).show();
                }
            }
        }
    }
}

如下图
在这里插入图片描述

如上面的写法确实可以对工厂进行很好的扩展
但确实,每增加一个类都要改一下我们的抽象工厂类,还要添加实现子类。

如果要做的场景中存在多层结构,并且层与层之间存在相应依赖和联系,则可以考虑使用抽象工厂模式。

今天就到这,设计模式系列文章,我会继续做的,把我认为几个经常会用到的再做一个我个人的总结吧!

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值