美文网首页
工厂方法模式

工厂方法模式

作者: Tyhj | 来源:发表于2019-01-30 15:05 被阅读0次

    感觉工厂方法模式,是有点难理解的;所以先讲讲使用方法,再谈谈理解

    定义

    定义一个用于创建对象的接口,让子类决定实例化哪个类

    使用场景

    在任何需要生成复杂对象的地方,都可以使用工厂方法模式

    举个栗子

    比如数据存储,APP一般可以将数据保存在内存、数据库、服务器这三个地方;对数据的操作,一般就是增删改查,所以我们抽象出产品类;

    public interface IoHandler {
        /**
         * 保存
         */
        void save();
    
        /**
         * 删除
         */
        void delete();
    
        /**
         * 更新
         */
        void update();
    }
    

    然后具体产品类,就是实现接口保存数据到数据库

    public class SqlLiteHandler implements IoHandler {
        @Override
        public void save() {
            //保存数据到数据库
        }
    
        @Override
        public void delete() {
    
        }
    
        @Override
        public void update() {
    
        }
    }
    

    就是实现接口保存数据到后台

    public class ServerHandler implements IoHandler {
        @Override
        public void save() {
            //保存数据到后台
        }
    
        @Override
        public void delete() {
    
        }
    
        @Override
        public void update() {
    
        }
    }
    

    简单工厂模式

    创建一个简单的工厂

    public class IoFactory {
        public static IoHandler getIoHandler(String type) {
            IoHandler ioHandler = null;
            if (type.equals("server")) {
                ioHandler = new ServerHandler();
            } else if (type.equals("sqllite")) {
                ioHandler = new SqlLiteHandler();
            }
            return ioHandler;
        }
    }
    

    调用也很简单

    ServerHandler handler = IoFactory.getIoHandler("server");
    

    工厂方法模式

    上面的工厂有一个问题,不符合开闭原则,新增数据保存方式的时候需要修改IoFactory,容易出错;解决方法,很简单,抽象出创建产品的接口

    public interface IoFactory {
        /**
         * 创建IoHandler
         * @return
         */
        IoHandler createIoHandler();
    }
    

    实现接口,实现创建ServerHandler的工厂,创建SqlLiteHandler工厂方法也是一样

    public class ServerFactory implements IoFactory {
        @Override
        public IoHandler createIoHandler() {
            return new ServerHandler();
        }
    }
    

    具体调用

    ServerHandler handler = new ServerFactory().createIoHandler();
    

    符合了开闭原则,新增一种保存方法不会影响之前的代码;每一个保存方法需要新建一个工厂,稍微有些麻烦,还有一种简洁的写法,利用反射来生产具体的对象

    public interface IoFactory {
        /**
         * 创建IoHandler
         *
         * @param tClass
         * @param <T>
         * @return
         */
        <T extends IoHandler> T createIoHandler(Class<T> tClass);
    }
    

    具体的工厂类通过反射就可以获取

    public class IoHandlerFactory implements IoFactory {
    
        @Override
        public <T extends IoHandler> T createIoHandler(Class<T> tClass) {
            IoHandler ioHandler = null;
            try {
                ioHandler = (IoHandler) Class.forName(tClass.getName()).newInstance();
            } catch (Exception e) {
                e.printStackTrace();
            }
            return (T) ioHandler;
        }
    }
    

    具体调用

    ServerHandler serverHandler=new IoHandlerFactory().createIoHandler(ServerHandler.class);
    SqlLiteHandler sqlLiteHandler=new IoHandlerFactory().createIoHandler(SqlLiteHandler.class);
    

    抽象工厂模式

    其实抽象工厂模式工厂方法模式差不多,区别就是工厂方法模式一个工厂只能做一件事,比如创建一个IoHandler对象;抽象工厂模式不只是创建一个IoHandler,还得创建其他相关的对象出来;就是一个创建一组相关产品的工厂吧;实现方法和工厂方法模式一样,只是多了几种产品,抽象出来的工厂类多几个抽象方法,用来创建多的几个抽象产品,当然因为产品多了,实现的工厂类可以对产品进行组合,也更多了;

    简单举个小例子

    网上买电脑,CPU主板一起买会便宜不少,店铺一般也会给出几种搭配,我们选择其中一种就行了

    抽象出CPU来

    public interface Cpu {
        /**
         * CPU型号
         * @return
         */
        void cpuName();
    }
    

    AMD的1500X,ACpu

    public class ACpu implements Cpu {
        @Override
        public void cpuName() {
            System.out.println("Ryzen 5 1500X");
        }
    }
    

    Intel的i7 9700k,ICpu

    public class ICpu implements Cpu{
        @Override
        public void cpuName() {
            System.out.println("i7 9700k");
        }
    }
    

    抽象出主板来

    public interface MotherBoard {
        /**
         * 主板型号
         *
         * @return
         */
        void boardName();
    }
    

    Z390主板

    public class BoardZ390 implements MotherBoard{
        @Override
        public void boardName() {
            System.out.println("Z390-PLUS GAMING");
        }
    }
    

    B250主板

    public class BoardB250 implements MotherBoard{
        @Override
        public void boardName() {
            System.out.println("MSI B250");
        }
    }
    

    抽象出套餐工厂

    public interface ComputerFactory {
    
        /**
         * 组装CPU
         *
         * @return
         */
        Cpu buildCpu();
    
        /**
         * 组装主板
         *
         * @return
         */
        MotherBoard buildBoard();
    
    }
    

    Z390主板加i7CPU的高配套装

    public class HighwithFactory implements ComputerFactory {
        @Override
        public Cpu buildCpu() {
            return new ICpu();
        }
    
        @Override
        public MotherBoard buildBoard() {
            return new BoardZ390();
        }
    }
    

    B250主板加上1500X的中配套餐

    public class MediumFactory implements ComputerFactory {
        @Override
        public Cpu buildCpu() {
            return new ACpu();
        }
    
        @Override
        public MotherBoard buildBoard() {
            return new BoardB250();
        }
    }
    

    现在要选择高配的套餐

    ComputerFactory computerFactory=new HighwithFactory();
    computerFactory.buildBoard().boardName();
    computerFactory.buildCpu().cpuName();
    

    输出

    Z390-PLUS GAMING
    i7 9700k

    但是当我把显卡、内存条、硬盘、机箱都加进来,高低配硬件也进行组合,组合就会变得很多,而套餐(工厂)就会变得非常多,就会创建非常多的类,因此开发中需要谨慎使用

    工厂方法的理解

    需要抽象出产品,抽象出工厂,实现不同的工厂去创建不同的产品;抽象这种东西,在六大基本原则就知道了,抽象是要抽象的,问题是为什么还需要一个工厂呢,直接new一个产品不行吗?感觉像是构造者模式的Director部分一样,没什么用呀

    有这个疑问也很正常,我在看了这篇文章(工厂设计模式有什么用?)后,好像有了一点点理解;本质上是封装了new一个具体的classA的细节,将变化控制在工厂之中;如果classA的构造改变了,或者需要改为使用classB了,可以在工厂方法里面修改而不需要修改调用者,这样实现解耦,遵循开闭原则

    我感觉好像和依赖注入差不多一个意思,我们为了不耦合,所以不自己去创建对象,使用注入进来的对象,现在我们为了不耦合也可以使用工厂注入对象,可能差不多吧

    总结

    感觉大概多使用就理解了吧

    相关文章

      网友评论

          本文标题:工厂方法模式

          本文链接:https://www.haomeiwen.com/subject/hohcsqtx.html