zoukankan      html  css  js  c++  java
  • 大话设计模式:工厂模式

    SimpleFactory

    说到工厂,我们应该能想到,造汽车的有汽车工厂,造轮船的有轮船工厂,映射到Java中,造对象的就应该有对象工厂,比如说我想要买一辆车,那我只需要去汽车工厂(先不去4S店)里面告诉它什么品牌的汽车,具体参数,给钱提车就完了,我并不需要了解汽车是如何造出来的,也就是屏蔽了造车的细节,这样的好处就是对于买家来说,简单方便,用户体验大大提升,对于卖家来说我厂生产汽车的具体细节不会外露。

    需求:

    用户提出要圆形、三角形、菱形等等。

    解决方案1:

    public void m1() {
        // 用户需要圆,自己new一个
        Circle circle = new Circle();
        // 用户需要三角形,自己new一个
        Triangle triangle = new Triangle();
    }
    

    解决方案2:

    可以使用简单工厂的模式,只需要将工厂暴露给调用方,调用方给出自己想要的形状就可以了,因为所有的设计模式都是面向接口编程,所以接口是少不了的。

    定义一个Shape接口

    /**
     * Description: 所有图形都有的公共属性,定义成抽象类也可以,接口也可
     * @From www.zhangjianbing.com
     * @Author zhangjianbing
     */
    public interface Shape {
    
        void draw();
    
    }
    

    Shape接口的实现类CricleShape

    /**
     * Description: 圆形实例
     * @From www.zhangjianbing.com
     * @Author zhangjianbing
     */
    public class CircleShape implements Shape {
    
        public CircleShape() {
            System.out.println("圆形创建出来。");
        }
    
        @Override
        public void draw() {
            System.out.println("画出一个圆形。");
        }
    
    }
    

    Shape接口的实现类Triangle

    /**
     * Description: 三角形实例
     * @From www.zhangjianbing.com
     * @Author zhangjianbing
     */
    public class TriangleShape implements Shape {
    
        public TriangleShape() {
            System.out.println("三角形创建出来。");
        }
    
        @Override
        public void draw() {
            System.out.println("画出一个三角形");
        }
    
    }
    

    简单工厂类,对外暴露方法

    /**
     * Description: 简单工厂类
     * @From www.zhangjianbing.com
     * @Author zhangjianbing
     */
    public class ShapeFactory {
    
        /**
         * 1. 简单工厂模式对外屏蔽了对象的创建细节,需要什么对象直接从工厂获取。
         * 2. 将获取对象的方法声明成静态的,由工厂类,向外提供服务。
         */
        public static Shape getShape(String shapeName) {
            Shape shape = null;
            if (null != shapeName && !"".equals(shapeName)) {
                if ("circle".equalsIgnoreCase(shapeName)) {
                    shape = new CircleShape();
                } else if ("triangle".equalsIgnoreCase(shapeName)) {
                    shape = new TriangleShape();
                }
            }
            return shape;
        }
    
    }
    

    测试类

    在调用方只需要给工厂提供想要的形状即可,不必关心形状是如何来的。

    /**
     * Description: 简单工厂模式测试用例
     * @From www.zhangjianbing.com
     * @Author zhangjianbing
     */
    public class Test01 {
    
        @Test
        public void m1() {
            Shape circle = ShapeFactory.getShape("circle");
            circle.draw();
        }
    
    }
    

    简单工厂,根本来说不属于23中设计模式中的一种,但工厂方法模式和抽象工厂模式都是由它演变来的,它的缺点:系统扩展困难,一旦添加新产品就不得不修改工厂逻辑,有可能造成工厂逻辑过于复杂,违背了OCP原则。

    FactoryMethod

    还是上面的汽车例子,简单工厂类中维护了创建不同汽车的逻辑,比如说包括宝马,奔驰,奥迪,但后续需求越来越多,又增添了长城,马自达,大众等等品牌,那么这个工厂类的创建逻辑会越来越多,现实中,宝马有宝马自己的工厂,奔驰也有奔驰自己的工厂,映射到Java中,不同的类,应该有各自的工厂,这样的目的就是为了维护扩展方便,同时遵循了OCP原则。

    设计模式是基于接口的,首先要有一个汽车的接口Car,它用来规定汽车的公共功能:

    /**
     * Description: 所有汽车的公共接口
     * @From www.zhangjianbing.com
     * @Author zhangjianbing
     */
    public interface Car {
    
        /**
         * car在跑。
         */
        void running();
    
    }
    

    然后是具体品牌汽车的实例:

    宝马:

    /**
     * Description:
     * @From www.zhangjianbing.com
     * @Author zhangjianbing
     */
    public class BaoMa implements Car {
    
        @Override
        public void running() {
            System.out.println("宝马飞驰。");
        }
    
    }
    

    奔驰:

    /**
     * Description:
     * @From www.zhangjianbing.com
     * @Author zhangjianbing
     */
    public class BenChi implements Car {
    
        @Override
        public void running() {
            System.out.println("奔驰奔跑。");
        }
    
    }
    

    然后是各自品牌的工厂,在创建各自工厂之前,最好加一层汽车工厂接口,目的是用多态来返回不同的工厂,使代码更加灵活。

    汽车工厂接口:

    /**
     * Description:
     * @From www.zhangjianbing.com
     * @Author zhangjianbing
     */
    public interface CarFactory {
    
        Car createCar();
    
    }
    

    各自的汽车工厂类:

    宝马工厂:

    /**
     * Description:
     * @From www.zhangjianbing.com
     * @Author zhangjianbing
     */
    public class BaoMaFactory implements CarFactory {
    
        @Override
        public Car createCar() {
            System.out.println("宝马工厂生产汽车。");
            return new BaoMa();
        }
    
    }
    

    奔驰工厂:

    /**
     * Description:
     * @From www.zhangjianbing.com
     * @Author zhangjianbing
     */
    public class BenChiFactory implements CarFactory {
    
        @Override
        public Car createCar() {
            System.out.println("奔驰工厂生产汽车。");
            return new BenChi();
        }
    
    }
    

    测试类:

    /**
     * Description:
     * @From www.zhangjianbing.com
     * @Author zhangjianbing
     */
    public class Test01 {
    
        @Test
        public void m1() {
            // 1. 先获取宝马车的工厂,如果想改奔驰的,仅改动一行代码即可。
            CarFactory carFactory = new BaoMaFactory();
            // 2. 利用工厂来制造汽车
            Car car = carFactory.createCar();
            car.running();
        }
    
    }
    

    工厂方法模式就很利于扩展,且不需要改动原来的代码,不管增加多少个品牌,只需要增加对应的工厂,以及实例就好了。

    适用场景:

    1. 客户端不需要知道它所创建的对象的类。例子中我们不知道每个汽车具体叫什么名,只知道创建它的工厂名就完成了创建过程。
    2. 客户端可以通过子类来指定创建对应的对象。

    AbstractFactory

    抽象工厂的局限性比较大,并且它不符合OCP原则,工厂方法模式是创建一个对象,而抽象工厂它可以创建一组对象,这是和工厂方法模式最大的不同点。上述汽车的例子,假如汽车生产出来,出厂之前,我还需要给汽车做一个包装保养的服务,比如宝马有宝马的包装保养,奔驰有奔驰的包装保养,那是不是应该再创建一个专门做保养的工厂呢,肯定不是,抽象工厂的作用就是将汽车的生产、保养,以及后续的任务都做到一起,秉承一条龙服务,包括汽车的生产,包装,保养,维修等。

    首先定义基本接口:

    • 汽车公共接口Car:
    /**
     * Description:
     * @From www.zhangjianbing.com
     * @Author zhangjianbing
     */
    public interface Car {
    
        /**
         * car在跑。
         */
        void running();
        
    }
    
    • 汽车维修服务接口CarFix:
    /**
     * Description:
     * @From www.zhangjianbing.com
     * @Author zhangjianbing
     */
    public interface CarFix {
    
        /**
         * 汽车维修服务
         */
        void carFix(Car car);
    
    }
    
    • 汽车包装服务接口CarPack:
    /**
     * Description:
     * @From www.zhangjianbing.com
     * @Author zhangjianbing
     */
    public interface CarPack {
    
        /**
         * 汽车包装服务
         */
        void carPack(Car car);
    
    }
    

    三个接口的实现类:

    • Car类

    宝马BaoMa:

    /**
     * Description:
     * @From www.zhangjianbing.com
     * @Author zhangjianbing
     */
    public class BaoMa implements Car {
    
        @Override
        public void running() {
            System.out.println("宝马飞驰。");
        }
    
    }
    

    奔驰BenChi:

    /**
     * Description:
     * @From www.zhangjianbing.com
     * @Author zhangjianbing
     */
    public class BenChi implements Car {
    
        @Override
        public void running() {
            System.out.println("奔驰奔跑。");
        }
    
    }
    
    • 维修类CarFixService:
    /**
     * Description:
     * @From www.zhangjianbing.com
     * @Author zhangjianbing
     */
    public class CarFixService implements CarFix {
    
        @Override
        public void carFix(Car car) {
            System.out.println(car.getClass() + "在维修。");
        }
    
    }
    
    • 包装类CarPackService:
    /**
     * Description:
     * @From www.zhangjianbing.com
     * @Author zhangjianbing
     */
    public class CarPackService implements CarPack {
    
        @Override
        public void carPack(Car car) {
            System.out.println(car.getClass() + "精美包装。");
        }
    
    }
    

    抽象工厂:

    抽象工厂中提供了此工厂所有的服务以及功能,包括汽车生产、包装、维修等。

    /**
     * Description:
     * @From www.zhangjianbing.com
     * @Author zhangjianbing
     */
    public interface AbstractFactory {
    
        /**
         * 汽车创造
         */
        Car createCar();
    
        /**
         * 汽车修理服务
         */
        CarFix carFix(Car car);
    
        /**
         * 汽车包装服务
         */
        CarPack carPack(Car car);
    
    }
    

    具体的汽车工厂:

    奔驰工厂BenChiFactory:

    /**
     * Description:
     * @From www.zhangjianbing.com
     * @Author zhangjianbing
     */
    public class BenChiFactory implements AbstractFactory {
    
        @Override
        public Car createCar() {
            return new BenChi();
        }
    
        @Override
        public CarFix carFix(Car car) {
            return new CarFixService();
        }
    
        @Override
        public CarPack carPack(Car car) {
            return new CarPackService();
        }
    }
    

    宝马工厂BaoMaFactory:

    /**
     * Description:
     * @From www.zhangjianbing.com
     * @Author zhangjianbing
     */
    public class BaoMaFactory implements AbstractFactory {
    
        @Override
        public Car createCar() {
            return new BaoMa();
        }
    
        @Override
        public CarFix carFix(Car car) {
            return new CarFixService();
        }
    
        @Override
        public CarPack carPack(Car car) {
            return new CarPackService();
        }
    
    }
    

    测试类:

    /**
     * Description:
     * @From www.zhangjianbing.com
     * @Author zhangjianbing
     */
    public class Test01 {
    
        @Test
        public void m1() {
            // 1. 先按名字获取工厂
            AbstractFactory factory = new BenChiFactory();
            // 2. 生产车
            Car car = factory.createCar();
            // 3. 包装车
            CarPack carPack = factory.carPack(car);
            carPack.carPack(car);
            // 4. 上路
            car.running();
            // 5. 修理车
            CarFix carFix = factory.carFix(car);
            carFix.carFix(car);
            // -- 以上全部都是由工厂来完成。
        }
    
    }
    

    测试结果:

    生产奔驰。
    BenChi精美包装。
    奔驰奔跑。
    BenChi在维修。
    

    抽象工厂适用场景:

    1. 和工厂方法一样客户端不需要知道它所创建的对象的类。
    2. 需要一组对象共同完成某种功能时。并且可能存在多组对象完成不同功能的情况。
    3. 系统结构稳定,不会频繁的增加对象。(因为一旦增加就需要修改原有代码,不符合开闭原则)
  • 相关阅读:
    网站中三角小图标的制作方法
    table版网站首页制作
    网站首页之早期布局
    图标字体使用方法总结
    导航制作方法总结之二
    导航制作方法总结之一
    关于网站建设之清除浏览器默认样式
    MySql操作时间
    POI操作excel
    Spring定时器,定时执行(quartz)
  • 原文地址:https://www.cnblogs.com/zhangjianbing/p/13654908.html
Copyright © 2011-2022 走看看