zoukankan      html  css  js  c++  java
  • Spark小课堂Week7 从Spark中一个例子看面向对象设计

    Spark小课堂Week7

    从Spark中一个例子看面向对象设计

    今天我们讨论了个问题,来设计一个Spark中的常用功能。

    功能描述:数据源是一切处理的源头,这次要实现下加载数据源的方法load()

    初始需求

    需求:支持Json数据源加载
    具体:输入一个path,需要返回一个Relation,
    Relation中提供scan()和write()两个方法

    示意代码:

    class Context{
        public Relation json(String path){
            return new Relation(path);        
            }
    }
    
    class Relation{
        public Relation(path);
        public scan();
        public write();
    }
    

    第一次需求变化

    现在需要添加jdbc数据源,输入的是url和tableName,需要有自己的Relation实现

    简单实现:

    class Context{
        public JsonRelation json(String path){
            return new JsonRelation(path);        
            }
        public JdbcRelation jdbc(String url,String tableName){
            return new JdbcRelation(url,tableName);        
            }
    }
    
    class JsonRelation{
        public JsonRelation(String path);
        public scan();
        public write();
    }
    class JdbcRelation{
        public JdbcRelation(String url,String tableName);
        public scan();
        public write();
    }
    

    这个实现明显违反了开放封闭原则,增加一种文件格式,需要对核心类Context进行修改!!!

    方法整合

    所以首先,需要对json和jdbc方法进行合并为format,参数也进行合并,
    source参数表示数据源,是一个字符串,比如:"json"、"jdbc"
    逻辑整合起来

    class Context{
        public Relation format(String source,Map param){
             if(source == "json") return new JsonRelation(param.get("path"));
             if(source == "jdbc") return new JdbcRelation(param.get("url"),param.get("tableName"));
            ...
            }
    }
    
    class JsonRelation extends Relation{
        public JsonRelation(String path);
        public scan();
        public write();
    }
    class JdbcRelation extends Relation{
        public JdbcRelation(String url,String tableName);
        public scan();
        public write();
    }
    

    方法通用化。

    format方法还是违反了开放封闭原则。我们可以使用反射对其进行通用化。

    class Context{
        public Relation format(String source,Map param){
             Class c = Class.forName(source + "Relation");
             Constructor constructor= c.getDeclaredConstructor(Map.class);
             return constructor.newInstance(param);
            ...
            }
    }
    class JsonRelation extends Relation{
        public JsonRelation(Map param){
            this.path = param.get("path");        
            };
        public scan();
        public write();
    }
    class JdbcRelation extends Relation{
        public JdbcRelation(Map param){
            this.url = param.get("url");     
            this.tableName = param.get("tableName");
        }
        public scan();
        public write();
    }
    

    第二次需求变化

    需求:再增加一种文件类型csv,同样是输入path

    按照之前的思路,我们可以增加一个Relation类

    class CsvRelation extends Relation{
        public CsvRelation(Map param){
            this.path = param.get("path");        
            };
        public scan();
        public write();
    }
    

    这里有一个问题,我们其发现构造方法和JsonRelation是完全重复的,有没有办法消除这种重复

    消除重复,第一点是需要把重复的部分拆离出来。我们把Relation类拆分为Relation类和Provider类。其中Provider是一个工厂方法,通过反射来调用。

    class Context{
        public Relation format(String source,Map param){
             Class c = Class.forName(source + "Provider");
             Method method= c.getMethod("getRelation",Map.class);
             return method.invoke(null,param);
            ...
            }
    }
    class JsonProvider{
        public static createRelation(Param param){
                return new JSonRelation(param.get("path"));
            };
    }
    class JsonRelation extends Relation{
        public JsonRelation(String path);
        public scan();
        public write();
    }
    class CsvProvider{
        public static createRelation(Param param){
                return new CsvRelation(param.get("path"));
            };
    }
    class CsvRelation extends Relation{
        public CsvRelation(String path);
        public scan();
        public write();
    }
    class JdbcProvider{
        public static Relation createRelation(Param param){
                return new JdbcRelation(param.get("url"),param.get("tableName"));
            };
    }
    class JdbcRelation extends Relation{
        public JdbcRelation(String path,String tableName);
        public scan();
        public write();
    }
    

    Json和csv采用path构造,而jdbc使用url+table,这个可以认为是一个固有的规则,我们可以把构造中间重复的逻辑再单独抽取出来

    class Context{
        public Relation format(String source,Map param){
             Class c = Class.forName(source + "Provider");
             if(hasIntereface(c,PathProvider.class)){
                Method method= c.getMethod("getRelation",String.class);
                return method.invoke(null,param.get("path"));
                }
            if(hasIntereface(c,UrlProvider.class)){
                Method method= c.getMethod("getRelation",String.class,String.class);
                return method.invoke(null,param.get("url"),param.get("tableName"));            
            }   
            ...
            }
    }
    class JsonProvider implements PathProvider{
        public static createRelation(String path){
                return new JSonRelation(path);
            };
    }
    class CsvProvider implements PathProvider{
        public static createRelation(String path){
                return new CsvRelation(path);
            };
    }
    class JdbcProvider implements UrlProvider{
        public static Relation createRelation(String url,String tableName){
                return new JdbcRelation(url,tableName);
            };
    }
    
    

    然后,我们发现format方法中的实现有些太复杂,所以单独抽取出来

    class Context{
        public Relation format(String source,Map param){
                return Provider.getRelation(source,param);
            }
    }
    class Provider{
        public Relation getRelation(String source,Param,param){
             Class c = Class.forName(source + "Provider");
             if(hasIntereface(c,PathProvider.class)){
                Method method= c.getMethod("getRelation",String.class);
                return method.invoke(null,param.get("path"));
                }
            if(hasIntereface(c,UrlProvider.class)){
                Method method= c.getMethod("getRelation",String.class,String.class);
                return method.invoke(null,param.get("url"),param.get("tableName"));            
            }   
            ...
        }
    }
    

    小结

    未完待续。
    这个例子主要是进行对象的构造,是比较有通用性的。
    我们可以看到,面向对象设计中,主要是靠不同对象的特性来实现变化。
    而对于对象的构造会需要一些规则来驱动,这种规则我们一般抽象为接口来标识,
    处理这些规则的往往都是工厂方法,也是工厂的一个非常重要的作用。

  • 相关阅读:
    第一章 经济基础知识
    105_实例
    SQL开窗函数
    Docker教程:Docker入门实践
    102_HDFS分布式文件系统
    [转]远程连接出现身份验证错误,要求的函数不受支持
    flutter创建工程指定iOS及Android开发语言
    架构师学习之路:康威定律
    智能识别客户收货地址信息
    深入理解Apache Dubbo与实战 pdf
  • 原文地址:https://www.cnblogs.com/dt-zhw/p/5747255.html
Copyright © 2011-2022 走看看