zoukankan      html  css  js  c++  java
  • java23种设计模式——三、工厂模式

    源码在我的githubgitee中获取

    目录

    java23种设计模式—— 一、设计模式介绍
    java23种设计模式—— 二、单例模式
    java23种设计模式——三、工厂模式
    java23种设计模式——四、原型模式
    java23种设计模式——五、建造者模式
    java23种设计模式——六、适配器模式
    java23种设计模式——七、桥接模式
    java23种设计模式——八、组合模式

    工厂模式

    工厂模式介绍

    工厂模式是我们最常用的实例化对象模式了,是用工厂方法代替new操作的一种模式。著名的Jive论坛 ,就大量使用了工厂模式,工厂模式在Java程序系统可以说是随处可见。因为工厂模式就相当于创建实例对象的new,我们经常要根据类Class生成实例对象,如A a=new A() 工厂模式也是用来创建实例对象的,所以以后new时就要多个心眼,是否可以考虑使用工厂模式,虽然这样做,可能多做一些工作,但会给你系统带来更大的可扩展性和尽量少的修改量。(百度百科)
    工厂模式又分为:

    • 简单工厂模式:允许接口创建对象,但不会暴露对象的创建逻辑。
    • 工厂方法模式: 允许接口创建对象,但使用哪个类来创建对象,则是交由子类决定的
    • 抽象方法模式: 抽象工厂是一个能够创建一系列相关的对象而无需指定/公开其具体类的接口。该模式能够提供其他工厂的对象,在其内部创建其他对象。

    简单工厂模式

    属于创建型模式,又叫做静态工厂方法模式,不属于23种GOF设计模式之一。是由一个工厂对象决定创建出哪一种产品类的实例。违背“开放 - 关闭原则”,一旦添加新产品就不得不修改工厂类的逻辑,这样就会造成工厂逻辑过于复杂。

    假设现在有一家餐馆

    public interface Restaurant {
       public void cook();
    }
    

    餐馆有两种菜品:红烧肉和鸡蛋羹

    //鸡蛋羹
    public class Egg implements Restaurant {
        @Override
        public void cook() {
            System.out.println("鸡蛋羹做好了");
        }
    }
    
    //红烧肉
    public class Meet implements Restaurant{
        @Override
        public void cook() {
            System.out.println("红烧肉做好了");
        }
    }
    

    餐馆里有服务员,来负责向后厨传达客人的需求

    public class Waiter {
    	//同样可以定义常量然后通过switch语句来实现
        public static Restaurant getFood(String orderType) {
            Restaurant restaurant = null;
            if(orderType.equals("红烧肉")){
                restaurant = new Meet();
            }else if (orderType.equals("鸡蛋羹")){
                restaurant = new Egg();
            }
            return restaurant;
        }
    }
    

    现在顾客来了,要点一份红烧肉,就只需要和服务员说就行

    public class Customer {
        public static void main(String[] args) {
            Restaurant restaurant = Waiter.getFood("红烧肉");
            restaurant.cook();
        }
    }
    

    输出

    红烧肉做好了
    

    通过以上方法,的确实现了 提供创建实例的功能,而无需关心具体实现。但是我们不难发现,这种方法的扩展性很差,如果餐馆新出了一款菜品,还需要我们在服务员方法里修改。这使得当餐馆的菜品很多时,工厂方法代码逻辑将会非常复杂

    工厂方法模式

    工厂方法模式,又称工厂模式、多态工厂模式和虚拟构造器模式,通过定义工厂父类负责定义创建对象的公共接口,而子类则负责生成具体的对象。是在工厂模式家族中是用的最多模式,一般项目中存在最多的就是这个模式。是对简单工厂模式的一个优化,让每个对象都有一个与之对应的工厂。

    这里我们接着用上面的例子,假设这家餐厅的生意非常好,所以餐馆的老板把餐馆所有负责点餐的服务员都辞退了,取而代之的是添加了一个收银台,然后让每个厨师只负责做一样菜。这样客人只需要和收银台说要求就行了。

    这里我们接着用上面的类。除去服务员Waiter类

    新建Cashier接口

    /**
     * @author codermy
     * @createTime 2020/6/15
     */
    public interface Cashier {
        public Restaurant getFood();
    }
    

    然后给每一个菜品新建一个工厂类

    EggCooker

    /**
     * @author codermy
     * @createTime 2020/6/15
     */
    public class EggCooker implements Cashier {
        @Override
        public Restaurant getFood() {
            return new Egg();
        }
    }
    

    MeetCooker

    /**
     * @author codermy
     * @createTime 2020/6/15
     */
    public class MeetCooker implements Cashier{
        @Override
        public Restaurant getFood() {
            return new Meet();
        }
    }
    

    然后顾客点单只需要在收银台,餐厅的系统会自动将信息传递给相应的厨师,对应的厨师就能在餐馆中把菜做好

    /**
     * @author codermy
     * @createTime 2020/6/15
     * 消费者
     */
    public class Customer {
        public static void main(String[] args) {
            Cashier order = new EggCooker();
            Restaurant food = order.getFood();
            food.cook();
        }
    }
    

    输出结果

    鸡蛋羹做好了
    

    工厂方法模式解决了简单工厂模式不符合的开闭原则,当添加一个菜品时,只需要再雇佣一个厨师就行(从现实角度看,老板有点亏哦)。但是这也增加了系统的复杂度(菜越多,厨师就越多,这哪家餐馆顶的住)

    抽象工厂模式

    这个模式解决了每个工厂只能创建一类产品(工厂方法模式)的问题

    这里用餐馆的例子不太形象,不是很容易理解,强行举例可能会和上面的方法弄混,我自己绕了好一会,所以我们换一个例子。

    现在我们人手不离手机,我们假设手机有如下几个功能

    //手机产品接口
    public interface IphoneProduct {
        void callup();//打电话
        void sendSms();//发短信
    }
    

    每个人家里又都有路由器,路由器有如下功能

    //路由器产品接口
    public interface IRouterProduct {
        void openwifi();//开启wifi
        void setting();//设置wifi
    }
    

    然后现在有一个抽象产品工厂,是来生产这两样产品的,假设生产手机和路由器的方法是一样的,只是需要加上厂商信息

    //抽象产品工厂
    public interface IProductFactory {
        //生产手机
        IphoneProduct iphoneProduct();
        //生产路由器
        IRouterProduct iRouterProduct();
    }
    

    现在有两家厂商,小米和华为工厂,可以生产手机和路由器,他们两家厂商分别由两条产业线来做手机和路由器

    //小米手机
    public class XiaomiPhone implements IphoneProduct{
    
        @Override
        public void callup() {
            System.out.println("用小米手机打电话");
        }
    
        @Override
        public void sendSms() {
            System.out.println("用小米手机发短信");
        }
    }
    
    
    //小米路由器
    public class XiaomiRouter implements IRouterProduct {
    
        @Override
        public void openwifi() {
            System.out.println("打开小米wifi");
        }
    
        @Override
        public void setting() {
            System.out.println("设置小米wifi");
        }
    }
    
    
    //小米厂商
    public class XiaomiFactory implements IProductFactory {
        @Override
        public IphoneProduct iphoneProduct() {
            return new XiaomiPhone();
        }
    
        @Override
        public IRouterProduct iRouterProduct() {
            return new XiaomiRouter();
        }
    }
    
    
    //华为手机
    public class HuaweiPhone implements IphoneProduct {
    
        @Override
        public void callup() {
            System.out.println("用华为手机打电话");
        }
    
        @Override
        public void sendSms() {
            System.out.println("用华为手机发短信");
        }
    }
    
    //华为路由器
        public class HuaweiRouter implements IRouterProduct {
    
            @Override
            public void openwifi() {
                System.out.println("打开华为wifi");
            }
    
            @Override
            public void setting() {
                System.out.println("设置华为wifi");
            }
        }
    
    //华为工厂
    public class HuaweiFactory implements IProductFactory {
        @Override
        public IphoneProduct iphoneProduct() {
            return new HuaweiPhone();
        }
    
        @Override
        public IRouterProduct iRouterProduct() {
            return new HuaweiRouter();
        }
    }
    

    消费者类

    //消费者/测试类
    public class Customer {
        public static void main(String[] args) {
    
            System.out.println("==============小米产品=================");
            XiaomiFactory xiaomiFactory = new XiaomiFactory();//新建一个小米工厂
            IphoneProduct xiaomiiphoneProduct = xiaomiFactory.iphoneProduct();//小米工厂开始生产小米手机
            xiaomiiphoneProduct.callup();//测试小米手机打电话功能
            IRouterProduct xiaomiiRouterProduct = xiaomiFactory.iRouterProduct();//小米工厂开始生产小米路由器
            xiaomiiRouterProduct.openwifi();//测试小米路由器打开wifi功能
    
            System.out.println("==============华为产品=================");
            HuaweiFactory huaweiFactory = new HuaweiFactory();
    
            IphoneProduct huaweiiphoneProduct1 = huaweiFactory.iphoneProduct();
            huaweiiphoneProduct1.callup();
            IRouterProduct huaweiiRouterProduct = huaweiFactory.iRouterProduct();
            huaweiiRouterProduct.openwifi();
        }
    }
    

    输出

    ==============小米产品=================
    用小米手机打电话
    打开小米wifi
    ==============华为产品=================
    用华为手机打电话
    打开华为wifi
    

    抽象工厂模式相较于以上两种模式难以理解一些。这里提供另一种写法比较好理解,来自Guide哥的博客(以下所有内容)

    不知道大家玩过穿越火线或者吃鸡这类游戏了吗,游戏中存在各种枪。我们假设现在存在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
    
  • 相关阅读:
    vnpy源码阅读学习(8):关于app
    vnpy源码阅读学习(6):事件引擎
    vnpy源码阅读学习(5):关于MainEngine的代码阅读
    tensorflow 2.1 采坑记
    vnpy源码阅读学习(4):自己写一个类似vnpy的UI框架
    ABP (.Net Core 3.1版本) 使用MySQL数据库迁移启动模板项目(1)
    'vue-cli-service' 不是内部或外部命令,也不是可运行的程序 或批处理文件。
    C# Winform版批量压缩图片程序
    小程序开发技巧总结
    ASP.NET WebAPI 双向token实现对接小程序登录逻辑
  • 原文地址:https://www.cnblogs.com/codermy/p/13569486.html
Copyright © 2011-2022 走看看