zoukankan      html  css  js  c++  java
  • 设计模式-Factory

    设计模式------工厂模式

    工厂模式的定义:实例化对象,用工厂方法替代new操作,达到解耦的目的。
    使用的场景:在需要生成复杂对象的地方,可以使用工厂方法模式。直接用new 可以完成的不需要工厂模式。

    首先看4类工厂的结构图,对比可以发现它们的不同:

    简单(静态)工厂:

    abstract class INoodles {
        public abstract void desc();//面条描述
    }
    
    //具体类
    class LzNoodles extends INoodles {
    
        @Override
        public void desc() {
            System.out.println("兰州拉面");
        }
    
    }
    
    class PaoNoodles extends INoodles {
    
        @Override
        public void desc() {
            System.out.println("泡面");
        }
    
    }
    
    class GankouNoodles extends INoodles {
    
        @Override
        public void desc() {
            System.out.println("干扣面");
        }
    
    }
    // 简单工厂(面馆)
    class SimpleNoodlesFactory {
        public static final int TYPE_LZ = 1;// 兰州拉面
        public static final int TYPE_PM = 2;// 泡面
        public static final int TYPE_GK = 3;// 干扣面
        
        public static INoodles createNoodles(int type) {
            switch (type) {
            case TYPE_LZ:
                return new LzNoodles();
            case TYPE_PM:
                return new PaoNoodles();
            case TYPE_GK:
            default:
                return new GankouNoodles();
            }
        }

    简单工厂特点:
    (1) 它是一个具体的类,非接口 抽象类。有一个重要的create()方法,利用if或者 switch创建产品并返回。
    (2) create()方法通常是静态的,所以也称之为静态工厂。
    缺点:
    (1) 扩展性差(我想增加一种面条,除了新增一个面条产品类,还需要修改工厂类方法)
    (2) 不同的产品需要不同额外参数的时候 不支持
    // 简单工厂(反射)
    利用反射Class.forName(clz.getName()).newInstance() 实现的简单工厂

    class StaticNoodlesFactory {
        //传入Class实例化面条产品类
        public static <T extends INoodles> T createNoodles(Class<T> clz) {
            T result = null;
            try {
                result = (T) Class.forName(clz.getName()).newInstance();
            } catch (Exception e) {
                e.printStackTrace();
            }
            return result;
        }
    }

    特点:
    (1) 它也是一个具体的类,非接口 抽象类。但它的create()方法,是利用反射机制生成对象返回,好处是增加一种产品时,不需要修改create()的代码。
    缺点:这种写法粗看牛逼,细想之下,不谈reflection的效率还有以下问题:
    (1) 个人觉得不好,因为Class.forName(clz.getName()).newInstance()调用的是无参构造函数生成对象,它和new Object()是一样的性质,而工厂方法应该用于复杂对象的初始化 ,当需要调用有参的构造函数时便无能为力了,这样像为了工厂而工厂。
    (2) 不同的产品需要不同额外参数的时候 不支持。
    //多方法工厂

    class MulWayNoodlesFactory {
    
        public static INoodles createPm() {
            return new PaoNoodles();
        }
    
        public static INoodles createLz() {
            return new LzNoodles();
        }
    
        public static INoodles createGk() {
            return new GankouNoodles();
        }
    }

    这种我比较青睐,增加一个新面条,只要去增加一个static方法即可,也不修改原方法逻辑。

    上述实现的工厂,都有一个缺点:不同的产品需要不同额外参数的时候 不支持。

    而且如果使用时传递的type、Class出错,将不能得到正确的对象,容错率不高。

    而多方法的工厂模式为不同产品,提供不同的生产方法,使用时 需要哪种产品就调用该种产品的方法,使用方便、容错率高

    //普通工厂

    普通工厂就是把简单工厂中具体的工厂类,划分成两层:抽象工厂层+具体的工厂子类层

    abstract class NoodlesFactory {
        public abstract INoodles create();
    }
    
    class LzFactory extends NoodlesFactory {
        @Override
        public INoodles create() {
            return new LzNoodles();
        }
    }
    
    class PaoFactory extends NoodlesFactory {
        @Override
        public INoodles create() {
            return new PaoNoodles();
        }
    }
    
    class GankouFactory extends NoodlesFactory {
        @Override
        public INoodles create() {
            return new GankouNoodles();
        }
    }

    普通工厂与简单工厂模式的区别:
    普通工厂特点:不仅仅做出来的产品要抽象, 工厂也应该需要抽象。
    工厂方法使一个产品类的实例化延迟到其具体工厂子类.
    工厂方法的好处就是更拥抱变化。当需求变化,只需要增删相应的类,不需要修改已有的类。
    而简单工厂需要修改工厂类的create()方法,多方法静态工厂模式需要增加一个静态方法。
    缺点:引入抽象工厂层后,每次新增一个具体产品类,也要同时新增一个具体工厂类,所以我更青睐 多方法静态工厂。

    测试类

    public class Factory {
    
        public static void main(String[] args) {
         //简单工厂
    // INoodles noodles = // SimpleNoodlesFactory.createNoodles(SimpleNoodlesFactory.TYPE_GK); // noodles.desc();
         //简单工厂(反射)
    // INoodles lz = StaticNoodlesFactory.createNoodles(LzNoodles.class); // lz.desc();
         //多方法工厂
    // INoodles lz2 = MulWayNoodlesFactory.createLz(); // lz2.desc();

         //普通工厂 NoodlesFactory factory1 = new GankouFactory(); INoodles gk3 = factory1.create(); gk3.desc(); } }

    以上介绍的工厂都是单产品系的。抽象工厂是多产品系 (产品家族)。

     抽象工厂

    举个例子来说,每个店(工厂)不仅仅卖面条,还提供饮料卖。 提供饮料卖,饮料是产品,先抽象一个产品类,饮料:

    abstract class IDrinks {
        public abstract void prices();
    }
    
    class ColaDrinks extends IDrinks {
        @Override
        public void prices() {
            System.out.println("可乐三块五");
        }
    }
    
    class WaterDrinks extends IDrinks {
        @Override
        public void prices() {
            System.out.println("白开水,不要钱~!");
        }
    }
    
    abstract class AbstractFoodFactory {
        public abstract INoodles createNoodles();
    
        public abstract IDrinks createDrinks();
    }
    
    class LzlmFoodFactory extends AbstractFoodFactory {
        @Override
        public INoodles createNoodles() {
            return new LzNoodles();// 卖兰州拉面
        }
    
        @Override
        public IDrinks createDrinks() {
            return new WaterDrinks();// 卖水
        }
    }
    
    class KFCFoodFactory extends AbstractFoodFactory {
        @Override
        public INoodles createNoodles() {
            return new PaoNoodles();// KFC居然卖泡面
        }
    
        @Override
        public IDrinks createDrinks() {
            return new ColaDrinks();// 卖可乐
        }
    }

    //测试类
    public class Factory_Abs {
    
        public static void main(String[] args) {
         //抽象工厂 AbstractFoodFactory abstractFoodFactory1
    = new KFCFoodFactory(); abstractFoodFactory1.createDrinks().prices(); abstractFoodFactory1.createNoodles().desc(); abstractFoodFactory1 = new LzlmFoodFactory(); abstractFoodFactory1.createDrinks().prices(); abstractFoodFactory1.createNoodles().desc(); } }

    将工厂也抽象了,在使用时,工厂和产品都是面向接口编程,OO(面向对象)的不得了
    缺点:将工厂也抽象后,有个显著问题,就是类爆炸了。而且每次拓展新产品种类,例如不仅卖吃卖喝,我还想卖睡,提供床位服务,这需要修改抽象工厂类,因此所有的具体工厂子类,都被牵连,需要同步被修改。

    个人总结和使用场景
    一句话总结工厂模式:方便创建 同种产品类型的 复杂参数 对象
    工厂模式重点就是适用于 构建同产品类型(同一个接口 基类)的不同对象时,这些对象new很复杂,需要很多的参数,而这些参数中大部分都是固定的,so,懒惰的程序员便用工厂模式封装之。
    (如果构建某个对象很复杂,需要很多参数,但这些参数大部分都是“不固定”的,应该使用Builder模式)
    为了适应程序的扩展性,拥抱变化,便衍生出了 普通工厂、抽象工厂等模式。

  • 相关阅读:
    [转] 英语飙升的好方法
    jndi数据源方式配制SPY
    OJB查询
    ODP.NET应用之我所见
    C#中利用ODP实现瞬间导入百万级数据详解
    Sys.Extended.UI' is null or not an object 中文的訊息
    oracle数据库连接字符串
    seo
    宽幅FLASH产品展示代码多图带左右显示按钮 图
    网站盈利模式分类详解
  • 原文地址:https://www.cnblogs.com/songzongyuan-java/p/9462691.html
Copyright © 2011-2022 走看看