精华内容
下载资源
问答
  • 如何理解这6种常见设计模式

    千次阅读 2020-09-10 14:06:17
    有哪些常见的设计模式?如何合理运用?本文分享作者对工厂模式、单例模式、装饰模式、策略模式、代理模式和观察者模式的理解,介绍每种模式模式结构、优缺点、适用场景、注意实现及代码实现。一 前言最近在改造...
    简介:设计模式能够帮助我们优化代码结构,让代码更优雅灵活。有哪些常见的设计模式?如何合理运用?本文分享作者对工厂模式、单例模式、装饰模式、策略模式、代理模式和观察者模式的理解,介绍每种模式的模式结构、优缺点、适用场景、注意实现及代码实现。

    image.png

    一 前言

    最近在改造一些历史的代码,发现一个很明显的特点,大部分代码是记叙文,按照事件的发展过程将故事平铺直叙的讲解出来。

    这种方式的好处是比较符合人类的思维习惯,一条主线讲到底,代码阅读起来没有太大难度,只要顺着藤就能摸到瓜,但是缺点也很明显,一旦故事线中需要插入一些新的元素,比如:加入一个新的人物角色、新的时间线,都会需要大量更改故事线以配合这个新元素的融入,甚至对原有文章造成破坏性的影响。

    为了解决这个问题,人们总结出了很多种文章结构,例如:总-分结构,并列结构,总-分-总结构等等,有了这些结构,在加入新元素的时候,甚至不必考虑新元素与原故事情节的关联性,直接单拉一个分支故事线独立去讲就好了,只要能够在整体故事结束前,与汇聚到主线故事就可以了(是不是很像git?)。

    在软件开发领域,也有很多这样的非常有用的实践总结,我们称之为设计模式。对于设计模式,大家都不陌生,随便找个人,估计都能讲出N个设计模式来,但是除了这些设计模式的概念,很多人不知道如何灵活运用这些设计模式。所以借这篇文章和大家共同学习设计模式的思想。

    二 理解设计模式

    我尽量用最通俗易懂的示例和语言来讲述我理解的设计模式,希望能对大家有所帮助。

    另外也无需精通所有的设计模式,只要能够融汇贯通常见的设计模式,就能让你的代码变得优雅。就像程咬金只会三板斧,但是熟练度无人能及,照样能横行天下。

    1 工厂模式(Factory)

    简单工厂(Simple Factory)

    小明追妹子的时候,请她喝了不少咖啡,她爱喝卡布奇诺,每次去咖啡店,只要跟服务员说“来杯卡布奇诺”就行了,虽然各家的口味有些不同,但是不管是星爸爸还是Costa,都能够提供卡布奇诺这种咖啡。这里的星爸爸和Costa就是生产咖啡的工厂。

    (1)简单工厂模式结构

    简单工厂模式包含如下角色:

    • Factory:工厂角色-负责实现创建所有实例的内部逻辑.
    • Product:抽象产品角色-是所创建的所有对象的父类,负责描述所有实例所共有的公共接口。
    • ConcreteProduct:具体产品角色-是创建目标,所有创建的对象都充当这个角色的某个具体类的实例。

    结构图:

    image.png

    时序图:
    image.png

    (2)优缺点

      • 优点:客户类和工厂类分开。消费者任何时候需要某种产品,只需向工厂请求即可。消费者无须修改就可以接纳新产品。
    • 缺点:是当产品修改时,工厂类也要做相应的修改。

    工厂方法(Factory Method)

    以前经常带老婆去优衣库(简单工厂)买衣服,就那么多款式,逛的次数多了,她就烦了。后来我改变策略,带老婆去逛商场(抽象工厂),商场里有各式品牌的店铺,不用我管,她自己就能逛上一整天。
    区别于简单工厂,核心工厂类(商场)不再负责所有产品的创建,而是将具体创建的工作交给子类(服装店)去做,成为一个抽象工厂角色,仅负责给出具体工厂类必须实现的接口(门店),而不接触哪一个产品类应当被实例化这种细节。

    (1)工厂方法模式结构

    工厂方法模式包含如下角色:

    • Product:抽象产品
    • ConcreteProduct:具体产品
    • Factory:抽象工厂
    • ConcreteFactory:具体工厂

    结构图:
    image.png

    时序图:
    image.png

    工厂模式总结

    (1)适用场景

    输出的产品是标准品,谁来做都可以。

    (2)举例

    常见的数据库连接工厂,SqlSessionFactory,产品是一个数据库连接,至于是oracle提供的,还是mysql提供的,我并不需要关心,因为都能让我通过sql来操作数据。

    (3)注意事项

    项目初期,软件结构和需求都没有稳定下来时,不建议使用此模式,因为其劣势也很明显,增加了代码的复杂度,增加了调用层次,增加了内存负担。所以要注意防止模式的滥用。

    (4)简单实现

    package FactoryMethod;
    public class FactoryPattern
    {
        public static void main(String[] args)
    {
            Factory factory = new ConcreteFactoryA();
            Product product = factory.createProduct();
            product.use();
        }
    }
    //抽象产品:提供了产品的接口
    interface Product
    {
        public void use;
    }
    //具体产品A:实现抽象产品中的抽象方法
    class ConcreteProductA implements Product
    {
        public void use()
    {
            System.out.println("具体产品A显示...");
        }
    }
    //具体产品B:实现抽象产品中的抽象方法
    class ConcreteProductB implements Product
    {
        public void use()
    {
            System.out.println("具体产品B显示...");
        }
    }
    //抽象工厂:提供了厂品的生成方法
    interface Factory
    {
        public Product createProduct();
    }
    //具体工厂A:实现了厂品的生成方法
    class ConcreteFactoryA implements AbstractFactory
    {
        public Product createProduct()
    {
            System.out.println("具体工厂A生成-->具体产品A.");
            return new ConcreteProductA();
        }
    }
    //具体工厂B:实现了厂品的生成方法
    class ConcreteFactoryB implements AbstractFactory
    {
        public Product createProduct()
    {
            System.out.println("具体工厂B生成-->具体产品B.");
            return new ConcreteProductB();
        }
    }
    

    2 单例模式(Singleton)

    韦小宝有7个老婆,但是每个都只有他这一个老公,他的所有老婆叫老公时,指的都是他,他就是一个单例。

    单例模式结构

    单例模式包含如下角色:

    • Singleton:单例

    结构图:
    image.png

    时序图:

    image.png

    优缺点

    • 优点:全局只有一个实例,便于统一控制,同时减少了系统资源开销。
    • 缺点:没有抽象层,扩展困难。

    应用场景

    适合需要做全局统一控制的场景,例如:全局唯一的编码生成器。

    注意事项

    只对外提供公共的getInstance方法,不提供任何公共构造函数。

    简单实现

    public class Singleton
    {
        private static volatile Singleton instance=null;    //保证 instance 在所有线程中同步
        private Singleton(){}    //private 避免类在外部被实例化
        public static synchronized Singleton getInstance()
    {
            //getInstance 方法前加同步
            if(instance == null)
            {
                instance = new Singleton();
            }
            return instance;
        }
    }
    

    3 装饰模式(Decorator)

    大学毕业,想要送给室友一个有纪念意义的礼物,就找到一张大家的合照,在上面写上“永远的兄弟!”,然后拿去礼品店装了个相框,再包上礼盒。这里的我和礼品店都是装饰器,都没有改变照片本身,却都让照片变得更适合作为礼物送人。

    装饰模式结构

    装饰模式包含如下角色:

    • Component:抽象构件
    • ConcreteComponent:具体构件
    • Decorator:抽象装饰类
    • ConcreteDecorator:具体装饰类

    结构图:

    image.png

    时序图:

    image.png

    优缺点

    • 优点:比继承更加灵活(继承是耦合度很大的静态关系),可以动态的为对象增加职责,可以通过使用不同的装饰器组合为对象扩展N个新功能,而不会影响到对象本身。
    • 缺点:当一个对象的装饰器过多时,会产生很多的装饰类小对象和装饰组合策略,增加系统复杂度,增加代码的阅读理解成本。

    适用场景

    • 适合需要(通过配置,如:diamond)来动态增减对象功能的场景。
    • 适合一个对象需要N种功能排列组合的场景(如果用继承,会使子类数量爆炸式增长)

    注意事项

    • 一个装饰类的接口必须与被装饰类的接口保持相同,对于客户端来说无论是装饰之前的对象还是装饰之后的对象都可以一致对待。
    • 尽量保持具体构件类Component作为一个“轻”类,也就是说不要把太多的逻辑和状态放在具体构件类中,可以通过装饰类。

    简单实现

    package decorator;
    public class DecoratorPattern
    {
        public static void main(String[] args)
    {
            Component component = new ConcreteComponent();
            component.operation();
            System.out.println("---------------------------------");
            Component decorator = new ConcreteDecorator(component);
            decorator.operation();
        }
    }
    //抽象构件角色
    interface  Component
    {
        public void operation();
    }
    //具体构件角色
    class ConcreteComponent implements Component
    {
        public ConcreteComponent()
    {
            System.out.println("创建具体构件角色");       
        }   
        public void operation()
    {
            System.out.println("调用具体构件角色的方法operation()");           
        }
    }
    //抽象装饰角色
    class Decorator implements Component
    {
        private Component component;   
        public Decorator(Component component)
    {
            this.component=component;
        }   
        public void operation()
    {
            component.operation();
        }
    }
    //具体装饰角色
    class ConcreteDecorator extends Decorator
    {
        public ConcreteDecorator(Component component)
    {
            super(component);
        }   
        public void operation()
    {
            super.operation();
            addBehavior();
        }
        public void addBehavior()
    {
            System.out.println("为具体构件角色增加额外的功能addBehavior()");           
        }
    }
    

    4 策略模式(Strategy)

    男生追妹子时,一般都会用到这种模式,常见的策略有这些:约会吃饭;看电影;看演唱会;逛街;去旅行……,虽然做的事情不同,但可以相互替换,唯一的目标都是捕获妹子的芳心。

    策略模式结构

    • Context: 环境类
    • Strategy: 抽象策略类
    • ConcreteStrategy: 具体策略类

    结构图:
    image.png

    时序图:

    image.png

    优缺点

    • 优点:策略模式提供了对“开闭原则”的完美支持,用户可以在不修改原有系统的基础上选择算法或行为。干掉复杂难看的if-else。
    • 缺点:调用时,必须提前知道都有哪些策略模式类,才能自行决定当前场景该使用何种策略。

    试用场景

    一个系统需要动态地在几种可替换算法中选择一种。不希望使用者关心算法细节,将具体算法封装进策略类中。

    注意事项

    一定要在策略类的注释中说明该策略的用途和适用场景。

    简单实现

    package strategy;
    public class StrategyPattern
    {
        public static void main(String[] args)
    {
            Context context = new Context();
            Strategy strategyA = new ConcreteStrategyA();
            context.setStrategy(strategyA);
            context.algorithm();
            System.out.println("-----------------");
            Strategy strategyB = new ConcreteStrategyB();
            context.setStrategy(strategyB);
            context.algorithm();
        }
    }
    //抽象策略类
    interface Strategy
    {   
        public void algorithm();    //策略方法
    }
    //具体策略类A
    class ConcreteStrategyA implements Strategy
    {
        public void algorithm()
    {
            System.out.println("具体策略A的策略方法被访问!");
        }
    }
    //具体策略类B
    class ConcreteStrategyB implements Strategy
    {
      public void algorithm()
    {
          System.out.println("具体策略B的策略方法被访问!");
      }
    }
    //环境类
    class Context
    {
        private Strategy strategy;
        public Strategy getStrategy()
    {
            return strategy;
        }
        public void setStrategy(Strategy strategy)
    {
            this.strategy=strategy;
        }
        public void algorithm()
    {
            strategy.algorithm();
        }
    }
    

    5 代理模式(Proxy)

    淘宝店客服总是会收到非常多的重复问题,例如:有没有现货?什么时候发货?发什么快递?大量回答重复性的问题太烦了,于是就出现了小蜜机器人,他来帮客服回答那些已知的问题,当碰到小蜜无法解答的问题时,才会转到人工客服。这里的小蜜机器人就是客服的代理。

    代理模式结构

    代理模式包含如下角色:

    • Subject: 抽象主题角色
    • Proxy: 代理主题角色
    • RealSubject: 真实主题角色

    结构图:

    image.png

    时序图:

    image.png

    优缺点

    • 优点:代理可以协调调用方与被调用方,降低了系统的耦合度。根据代理类型和场景的不同,可以起到控制安全性、减小系统开销等作用。
    • 缺点:增加了一层代理处理,增加了系统的复杂度,同时可能会降低系统的相应速度。

    试用场景

    理论上可以代理任何对象,常见的代理模式有:

    • 远程(Remote)代理:为一个位于不同的地址空间的对象提供一个本地的代理对象,这个不同的地址空间可以是在同一台主机中,也可是在另一台主机中,远程代理又叫做大使(Ambassador)。
    • 虚拟(Virtual)代理:如果需要创建一个资源消耗较大的对象,先创建一个消耗相对较小的对象来表示,真实对象只在需要时才会被真正创建。
    • Copy-on-Write代理:它是虚拟代理的一种,把复制(克隆)操作延迟到只有在客户端真正需要时才执行。一般来说,对象的深克隆是一个开销较大的操作,Copy-on-Write代理可以让这个操作延迟,只有对象被用到的时候才被克隆。
    • 保护(Protect or Access)代理:控制对一个对象的访问,可以给不同的用户提供不同级别的使用权限。
    • 缓冲(Cache)代理:为某一个目标操作的结果提供临时的存储空间,以便多个客户端可以共享这些结果。
    • 防火墙(Firewall)代理:保护目标不让恶意用户接近。
    • 同步化(Synchronization)代理:使几个用户能够同时使用一个对象而没有冲突。
    • 智能引用(Smart Reference)代理:当一个对象被引用时,提供一些额外的操作,如将此对象被调用的次数记录下来等。

    简单实现

    package proxy;
    public class ProxyPattern
    {
        public static void main(String[] args)
    {
            Proxy proxy = new Proxy();
            proxy.request();
        }
    }
    //抽象主题
    interface Subject
    {
        void request();
    }
    //真实主题
    class RealSubject implements Subject
    {
        public void request()
    {
            System.out.println("访问真实主题方法...");
        }
    }
    //代理
    class Proxy implements Subject
    {
        private RealSubject realSubject;
        public void request()
    {
            if (realSubject==null)
            {
                realSubject=new RealSubject();
            }
            preRequest();
            realSubject.request();
            afterRequest();
        }
        public void preRequest()
    {
            System.out.println("访问真实主题之前的预处理。");
        }
        public void afterRequest()
    {
            System.out.println("访问真实主题之后的后续处理。");
        }
    }
    

    6 观察者模式(Observer)

    出差在外,想了解孩子在家的情况,这时候只要加入“相亲相爱一家人”群,老爸老妈会经常把孩子的照片和视频发到群里,你要做的就是作为一个观察者,刷一刷群里的信息就能够了解一切了。

    观察者模式结构

    观察者模式包含如下角色:

    • Subject:目标
    • ConcreteSubject:具体目标
    • Observer:观察者
    • ConcreteObserver:具体观察者

    结构图:

    image.png

    时序图:

    image.png

    优缺点

    • 优点:将复杂的串行处理逻辑变为单元化的独立处理逻辑,被观察者只是按照自己的逻辑发出消息,不用关心谁来消费消息,每个观察者只处理自己关心的内容。逻辑相互隔离带来简单清爽的代码结构。
    • 缺点:观察者较多时,可能会花费一定的开销来发消息,但这个消息可能仅一个观察者消费。

    适用场景

    适用于一对多的的业务场景,一个对象发生变更,会触发N个对象做相应处理的场景。例如:订单调度通知,任务状态变化等。

    注意事项

    避免观察者与被观察者之间形成循环依赖,可能会因此导致系统崩溃。

    简单实现

    package observer;
    import java.util.*;
    public class ObserverPattern
    {
        public static void main(String[] args)
        {
            Subject subject = new ConcreteSubject();
            Observer obsA = new ConcreteObserverA();
            Observer obsb = new ConcreteObserverB();
            subject.add(obsA);
            subject.add(obsB);
            subject.setState(0);
        }
    }
    //抽象目标
    abstract class Subject
    {
        protected List<Observer> observerList = new ArrayList<Observer>();   
        //增加观察者方法
        public void add(Observer observer)
        {
            observers.add(observer);
        }    
        //删除观察者方法
        public void remove(Observer observer)
        {
            observers.remove(observer);
        }   
        public abstract void notify(); //通知观察者方法
    }
    //具体目标
    class ConcreteSubject extends Subject
    {
       private Integer state;
       public void setState(Integer state){
            this.state = state;
    
            // 状态改变通知观察者
            notify();
        }
        public void notify()
        {
            System.out.println("具体目标状态发生改变...");
            System.out.println("--------------");       
    
            for(Observer obs:observers)
            {
                obs.process();
            }
    
        }          
    }
    //抽象观察者
    interface Observer
    {
        void process(); //具体的处理
    }
    //具体观察者A
    class ConcreteObserverA implements Observer
    {
        public void process()
        {
            System.out.println("具体观察者A处理!");
        }
    }
    //具体观察者B
    class ConcreteObserverB implements Observer
    {
        public void process()
        {
            System.out.println("具体观察者B处理!");
        }
    }

    原文链接:https://developer.aliyun.com/article/771958?

    版权声明:本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《阿里云开发者社区用户服务协议》和《阿里云开发者社区知识产权保护指引》。如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。
    展开全文
  • 程序设计范式,就是进行程序设计时的思维模式,每种程序设计范式都其自身的基本风格或典范模式。对一个问题进行分解,划分为各个子模块,对问题进行简化以便更容易地解决问题,这是人们普通采用的解决复杂问题的...

    从哲学和科学的角度来看,范式是指应用于某个领域的一 套明确的概念或思维模式,包括理论、研究方法、假设和标准。程序设计范式,就是进行程序设计时的思维模式,每种程序设计范式都有其自身的基本风格或典范模式。

    0645f274ffd7191a053f4358b64ec519.png

    对一个问题进行分解,划分为各个子模块,对问题进行简化以便更容易地解决问题,这是人们普通采用的解决复杂问题的思路。如何分解问题,从哪里着手分解,是程序设计范式首先要思考的问题。

    我们知道,过程范式解决问题的着眼点是动词,使用面向对象范式的程序员则是从名词入手来思考问题。动词代表的是功能,是要去做的事情,强调怎么做(how);名词代表的是对象,是做事情的主体或客体,强调谁做(who)。通常来说,对象的粒度比功能更大。对象不仅可以具有功能,还可以包含自身的属性。例如,某人具有不仅可以读书、写字、作画,还有自己的身高、长相、体重等。所以,一般来说, 用面向对象范式解决问题,设计效率比过程式更高。通俗地理解,如果想吃饭,可以自己到食堂去打饭(你重点关注的该是如何去食堂、怎么排队购买饭菜等),也可以请某位同学帮你带份饭菜回来(你重点关注的是请谁去、带什么饭菜)。前者就可以理解为过程范式,后者体现的就是面向对象范式思想。

    掌握了程序设计范式,就掌握了程序设计方法学。当前较为常见的程序设计范式有:

    (1)命令式(imperative): 使用语句来改变程序的状态。 与自然语言中的命令语气表示命令的方式一样,命令式程序由计算机执行的命令组成。命令式程序设计侧重于描述程序如何操作。它侧重于程序应该完成什么,而不指定程序应该如何实现结果。许多命令式程序设计语言(如FORTRAN、BASIC、 C等)都是汇编命令的抽象。

    (2)函数式(functional):一种构建计算机程序结构和构件的样式。它将计算处理为对数学函数的赋值,避免改变状态。函数式程序设计主要在学术界使用,但CommonLisp. Scheme、Clojure、 Wolfram (也称为Mathematica )、Racket、Erlang、Ocaml、Haskell、F#等也在被产业界的一些组织使用。一些特定领域的程序设计语言,如R (statistics)、J、K、Q、XQuery/XSLT(XML)、Opal、SQL、Lex/Yacc等也支持函数式程序设计范式。

    (3)声明式(declarative): 一种构建计算机程序结构和构件的样式。它表达的是不描述控制流的计算逻辑,侧重于程序达成什么结果,不指定该结果如何实现。当前常见的声明式程序设计语言包括数据库查询语言(如SQL、Xquery 等)、正则表达式、逻辑式程序设计、函数式程序设计,以及配置管理系统等。

    (4)面向对象式(object-oriented): 基于“对象”这个概念,把状态和修改状态的代码组织在一起。 许多使用最广泛的程序设计语言,如C、Object Pascal、Java、 Python等,都是多范式的程序设计语言。它们在一定程度上支持面向对象式、命令式、过程式等程序设计。当前的主流面向对象的语言包括Java、C++、 C#、Python、PHP、 Ruby、Perl、Object Pascal、Objective-C、Dart、Swift、Scala、Common Lisp 和 Smalltalk 等。

    (5)过程式(procedural): 源于结构化程序设计,基于过程调用的概念,把代码组织成功能模块(functions)。 过程,也称为例程(routine)、 子例程(subroutine) 或函数(function,不要与数学中的函数混淆,但类似于函数式程序设计中使用的函数),只是包含一系列要执行的计算步骤。 首批主要的过程式程序设计语言大约于1960出现,包括FORTRAN、Algol、COBOL 和 BASIC。Pascal 和 C发布于1970年左右, Ada 发布于1980年。Go发布于2009年,是一个更为现代化的过程式语言。

    (6)逻辑式(logic), 这是一种主要基于形式逻辑的程序设计范式,有特定语法风格的执行模型。任何用逻辑式程序设计语言编写的程序都是一组表达关于某个问题域的事实和规则的逻辑形式句子。逻辑式程序设计语言主要包括Prolog、 ASP (Answer Set Programming)、Datalog 等。

    (7)符号式(symbolic):在这种程序设计范式中,程序可以把自己的公式和程序组件当作普通数据一样进行操作。 把较小的逻辑单元或功能模块组合起来可以构建更为复杂的过程。这样的程序可以有效地修改自己,表现出一定的“学习”能力。因此,这种范式适合开发人工智能、专家系统、自然语言处理和计算机游戏这样的应用程序。支持符号式程序设计的语言有Wolfram、LISP、Prolog等。

    577f619eb5dfb0d7a5d57b0a8f89f20d.png
    展开全文
  • 很多同学在问:数据分析没有标准思路,没有分析思维模式。答案当然是:。但绝不是大家日常在公众号看到的各种炫酷名字。什么SOWT,PEST,二八法、切割法、多维法、业务法……这些名字炫酷余,可解决真实商业...

    很多同学在问:数据分析有没有标准思路,有没有分析思维模式。答案当然是:有。但绝不是大家日常在公众号看到的各种炫酷名字。什么SOWT,PEST,二八法、切割法、多维法、业务法……这些名字炫酷有余,可解决真实商业问题的时候没一个靠谱的。今天我们正本清源,一次性跟大家解释清楚:哪些数据思维的常见误区。

     

    误区一:数据分析思维是4P,4C,SWOT,PEST,五力模型……

    澄清:这些太过宏观,完全没法具体分析。

     

    这些概念是营销学、战略管理、产业经济等等课程的理论模型。在真实企业中,往往是一组人干的人,不是某一个人干的事。比如营销讲4P,在真实企业中,如果是传统企业,至少有一个营销总监管着营销部门,下边分为:产品管理、市场推广、品牌宣传、会员中心、促销活动、公关联盟等多个小组。如果是互联网公司,往往新客户获取由市场做,老客户维护由运营做。在运营里,又有用户运营、产品运营、活动运营、社群运营、新媒体运营、渠道运营、商品运营……

     

    每个部门的负责内容、工作流程、数据来源、考核KPI都不一样。不结合具体工作具体分析,而是洋洋洒洒写4P,每个P写了一堆东西,结果就是完全不具体,不知道给谁看,看了有什么用。那感觉,就像我们看大学生写的课后作业《腾讯发展的十大成功要点》一样

    (~ ̄▽ ̄)~

     

    优化策略:在企业里工作,要解决真实商业场景的真实问题,就要具体问题具体分析。

     

    做分析前,搞清楚我们是在服务:

    XX企业(行业、商业模式、发展阶段)

    XX部门(销售、市场、运营、供应链、风控……)

    XX小组(品牌、产品、活动、会员、公关、广告……)

    XX问题(我不知道目前情况,我们发现了XX问题,我们有XX困惑……)

    这样才能真正做出有商业价值,而不是自娱自乐的东西来

     

    误区二:数据分析思维是用户留存、用户画像……

    澄清:这些是具体的指标,是分析的素材,不是结果

     

    如果把题目完整,其实应该还有用户拉新、用户促活、用户留存、用户转化、用户推荐、用户画像……你看,这就是用户运营这个部门的工作内容吗。对应在数据上的,是一个具体的指标,比如:

     

    • 用户拉新(用户来源渠道、新用户数、拉新转化率、拉新漏斗、拉新质量)

    • 用户促活(用户活跃率、活跃用户质量、各层级用户活跃率)

    • 用户留存(次日、3日、7日、30日、季度、年度留存率;留存用户数)

    • 用户转化(转化率、转化行为、转化MOT、首次、二次、多次消费,RFM)

    • 用户推荐(参与率,有推荐行为人数、人均推荐人数、推荐质量)

    • 用户画像(以上所有指标+用户基础信息+用户设备信息)

     

    然而,单单列出这些指标,并没有达到“分析”的目的哦。比如用户留存,有的把用户登录APP定为留存,有的把消费定为留存,当定义不同时,留存含义都会变化,指向的业务动作当然也会变化。只看一个数值多少,是没法解答具体商业问题的。

     

    而且,针对留存这个问题,还有个经典困惑:如果我们把3个月内有付费定义为留存,一个月买1000产品,连续买3个月,和一次买6000,半年买一次的有什么区别?看似一次买6000,半年买一次是“流失”了,可有的消费者就是喜欢囤货,就是喜欢蹭618,双11(刚好上下半年各一次)……那这个定义本身都有问题,要怎么“分析呢?”

     

    优化策略:结合商业场景定义指标,从商业问题入手,而非从指标入手,构建分析思路。单纯看一个指标,屁都看不出来。可企业经营遇到的问题是活生生的:我们增长遭遇瓶颈,我们收入不够,我们的商业化速度太慢,怎么办!从这些具体痛点入手,把“增长遭遇瓶颈”对应到数据指标上(新用户数,GMV,……)这样就能真正开始脚踏实地的分析了。

     

    误区三:数据分析思维是象限法、多维法、二八法、对比法

    澄清:这些其实都是一个基础操作→分组对比。

    通过分组对比,找到数据差异。

    1. 二八法:一个指标按二八开做分组

    2. 象限法:两个指标,先各自分类,再交叉分组

    3. N个指标:聚类分析,聚成N组

     

    这些都是具体的分析手段,是分析的一个环节,不是分析本身。如果大家把它和上一个误区连起来看,就发现其实两者是一脉相承的。有了指标,没有标准,拿什么判断好坏!于是需要对指标做分类对比,先树立起“好/坏”的标准。或者业务上已经有了“好/坏”的定义,我们做分组对比,看看“好”到底在哪里好,“坏”到底在哪里坏,明确一个清晰的数量分界线,这样才好做后续深入分析。

     

    优化策略:标准至关重要,数据+标准=判断。有了判断才能深入分析。因此没有标准,就通过分组对比找标准。有标准,通过分析对比,找到“好/坏”的点。分组的方式可以根据数据多寡来选。但思路一定要清晰。经常有同学来问老师:老师,我要聚类,我有一堆数据,我该怎么聚?老师肯定反问:你想聚了干什么啊。去餐馆吃饭,你都得先问客人:客官想吃点什么。而不是在这想:我有大米、蘑菇、牛肉、所以我要怎么做客人才爱吃呢?

     

    误区四:数据分析思维是漏斗法、多维法

    澄清:这些其实是一个基础操作→构建指标体系。

    指标背后具体商业动作,指标体系是按商业动作的逻辑,把一顿指标串行/并起来,从而观察商业问题的基本方法。单一的指标本身就是很难说明问题的。

     

    商业动作的逻辑关系有两个基本类型。一类是串行关系,比如用户看到我们的站外广告然后到网站注册买东西,就有看到广告→落地页→注册→浏览→购买,这样一个顺序动作。需要先做完一个再做另一个。每一步会损失一些用户,因此摆在一起像个漏斗,是所谓漏斗法。其实只要是串行指标都能做漏斗,不限于“互联网AARRR漏斗”。比如B2B企业的跟单,就是一个典型串行关系:接受销售线索→首次联系→二次跟进→打样→竞标→签合同

     

    另一类是并行关系。比如用户购买会带来收入和利润。

    • 利润=收入-成本

    • 收入=销售收入+广告收入+投资收入

    • 销售收入=日用+百货+3C+餐饮+……

     

    这种整体与局部、总分关系的都是并行关系。基于这种关系有一个分析方法叫杜邦分析法。在追查问题的时候,可以从总体到局部,从宏观到细节层层深入,比如发现利润未达预期,再往下看,是收入不够,还是成本飙升;再往下看是哪些区域、产品、用户贡献的收入不够;哪些项目成本飙升。这样的推进方式,是所谓“多维法”“分解法”“拆解法”——其实就是总分看数的意思。

     

    优化策略:

    其实看完前四个误区,大家已经发现了,本质问题是,这四种误区其实是一件事,就是:把一个完整的分析思路,人为割裂成若干个炫酷的名字。名字看起来是牛逼了,可真正操作的时候,单纯靠某个环节是无法解决问题的。真正做分析,是把上边四类打通,一步步的深入,逐渐逼近真相。要

     

    1. 理解商业背景

    2. 建立指标,用数据说话

    3. 明确指标背后的商业含义

    4. 把商业问题转化为可量化的数据问题

    5. 梳理指标关系,建立指标体系

    6. 寻找判断问题的标准

    7. 按图索骥,找到问题点

    8. 提出假设,推测原因

    9. 验证假设,归纳结论

    10. 提出预测,判断走势

    11. 跟踪走势,发现新问题

     

    如此循环往复,逐步积累经验,就会分析的越来越准确。只可惜这个过程太复杂,需要一步步详细解释。因此很难给新人们直观的感受,并且不够炫酷啊!新人们总在问:分析思维模型是什么?老师你有哪些模型可以讲?于是为了吸引新人,很多教数据分析的老师就忍痛割爱,咔嚓几刀把原本完整的分析思路切成“矩阵模型”“二八模型”。看起来卖相好多,哈哈。

     

    如果把上边的一堆方法,连同统计学方法打包,大概可以归纳如下

     

    当然,还有一类误区是直接把统计学方法当做数据分析方法。不过这个误区一般存在于没有见过真实商业数据的在校学生群体。真正进入企业工作后,大家都被糟糕的数据质量和混乱的问题搞得晕头转向,没人迷信这个了。

    转自:https://www.itcodemonkey.com/article/15101.html

    展开全文
  • Java面试常见问题

    2020-06-24 15:36:58
    而面向对象的思维是市面上有哪些现成的连接池,我们拿来来用 再比如软件开发的三层结构(UI层、业务层、数据持久层) 面向对象会去选市面上优秀的框架,做一个选择,而面向过程就是在造轮子。 面向对象有三大特性...

    01对面向对象的理解

    面向对象是以“组织者”的思维模式来考虑问题
    面向过程是以“执行者”的思维模式来考虑问题
    比如我们要做一些数据库的连接或者说封装操作。
        面向过程想的是我要怎么来创造一个连接池的对象,怎么去管理
        而面向对象的思维是市面上有哪些现成的连接池,我们拿来来用
    再比如软件开发的三层结构(UI层、业务层、数据持久层)
        面向对象会去选市面上优秀的框架,做一个选择,而面向过程就是在造轮子。
    面向对象有三大特性:封装继承和多态
    继承为了复用,抽取共性的东西;多态父类引用指向子类对象,拿来解耦
    

    02JDK,JRE,JVM的区别’

    JDK(Java Development Kit) 是整个JAVA的核心,包括了Java运行环境(Java Runtime Envirnment),一堆Java工具(javac/java/jdb等)和Java基础的类库(即Java API 包括rt.jar)。
    JRE(Java Runtime Environment,Java运行环境),包含JVM标准实现及Java核心类库。JRE是Java运行环境,并不是一个开发环境,所以没有包含任何开发工具(如编译器和调试器)
    JVM(Java Virtual Machine),即java虚拟机, java运行时的环境,实现一次编译到处运行。
    JVM不能单独搞定class的执行,解释class的时候JVM需要调用解释所需要的类库lib。
    在JDK下面的的jre目录里面有两个文件夹bin和lib,在这里可以认为bin里的就是jvm,lib中则是jvm工作所需要的类库,而jvm和 lib和起来就称为jre。JVM+Lib=JRE。
    总体来说就是:
        我们利用JDK(调用JAVA API)开发了属于我们自己的JAVA程序后,
        通过JDK中的编译程序(javac)将我们的文本java文件编译成JAVA字节码,
        在JRE上运行这些JAVA字节码,JVM解析这些字节码,映射到CPU指令集或OS的系统调用。
    

    03 ==和equals的区别

    两者默认情况下都是比较地址
    ==:在比较基本数据类型时,比较的是数值
        在比较引用类型时,比较的是引用指向的值(地址)
    equals默认比较的是地址,如果要比较内容需要重写equals方法
    

    04 final关键字的使用

    final修饰类:表示类不可变不可被继承,比如String,不可变性
    final修饰方法:表示该方法不可被重写,比如模版,固定的算法
    final修饰变量:这个变量就为一个常量
    修饰的是基本数据类型,这个值本身不可被修改
    修饰的是引用类型,引用的指向(地址)不可被修改
    使用final方法的原因有两个。第一个原因是把方法锁定,以防任何继承类修改它的含义;第二个原因是效率
    final, finally, finalize的区别
        final 用于声明属性,方法和类,分别表示属性不可变,方法不可覆盖,类不可继承。
        finally是异常处理语句结构的一部分,表示总是执行。
        finalize是Object类的一个方法,在垃圾收集器执行的时候会调用被回收对象的此方法,可以覆盖此方法提供垃圾收集时的其他资源回收,例如关闭文件等。
    

    05 String,StringBuffer,StringBuilder区别

    String:是final类型,每次声明都是不可变的对象
            每次操作都会产生新的对象,然后指针也指向新的对象
    (字符拼接问题)
    StringBuffer和StringBuilder:是在原有对象上进行操作,都可进行修改
    2.在单线程且操作大量字符串用StringBuilder,速度快,但线程不安全;
    3.在多线程且操作大量字符串用StringBuffer,线程安全。
        为什么安全:因为他的每个方法都加了synchronized(同步)关键字
        考虑安全场景:多线程访问同一个共享资源时
    线程安全:多线程条件下对这个对象访问不用加其他任何东西访问操作数据的结果依然是正确的
    

    06接口和抽象类的区别

    从语法上讲:
        抽象类:可以理解为声明方法的存在而不去实现它的类,
                其类中的方法可以有抽象的也可以有非抽象的和构造器
                其子类,要重写其所有的抽象方法否则它们也是抽象类为。
        接口:是抽象类的变体,他里面的方法都是抽象的,属性都是常量,默认有public static final修饰
    从设计上讲:
        抽象类:是对同一类事物的抽取,比如在开发中我们在针对Dao层操作时会抽取一个基础的BaseDao,这样能做到复用效果
        接口:通常更像是一个标准的制定,定制系统间的对接
            比如:在单体架构中,我们进行分层开发,为了解耦我们会用接口作为各层间的纽带,绕
            在controller注入IUserService,在Service注入IuserDao,这样有利于我们开发中秉承高内聚低耦合的原则
        
    区分几个概念:
        多重继承:爷孙三代关系
        多实现:Person implement iruanble,ieateble
        多继承:接口可以,类不行    
    

    07算法题

    求N的阶乘
    递归:方法内部调用该方法,注意找到规律和出口
        会出现的问题是:栈内存溢出,因为每次调用方法都会在栈内存开辟空间
    必须要会自己手写
    public static int getResult(int n){
        if(n<0){
            throw new ValitoExcption("非法参数");
        }
        if(n==0||n==1){
            return 1;
        }
        return getResult(n-1)*n
    }
    
    求斐波那切数列的地N个数是几
    数字规律:1,1,2,3,5,8,13,21...
    出口:第一项和第二项都等于1
    public static int getResult(int n){
        if(n<0){
            throw new ValitoExctption("非法参数");
        }
        if(n==1||n==2){
            return 1;
        }
        return getResult(n-1)+getResult(n-2);
    }
    

    08Integer&int(缓存&自动装箱和拆箱)

    Java是一个近乎纯洁的面向对象编程语言,但是为了编程的方便还是引入了基本数据类型
    但是为了能够将这些基本数据类型当成对象操作,Java为每一个基本数据类型都引入了对应的包装类型
    int的包装类就是Integer,从Java5开始引入了自动装箱/拆箱机制,使得二者可以相互转换。
    Java 为每个原始类型提供了包装类型:
    - 原始类型: boolean,char,byte,short,int,long,float,double
    - 包装类型:Boolean,Character,Byte,Short,Integer,Long,Float,Double
    如果整型字面量的值在-128到127之间,那么不会new新的Integer对象,而是直接引用常量池中的Integer对象
    

    09方法的重写和重载的区别

    是Java多态性的不同表现
    重载:发生在一个类里面,方法名相同,参数列表不同(跟返回型没关系)
    重写:发生在父类子类之间,方法名相同,参数列表相同
    

    10List和Set区别

    List:有序,可重复(子类:ArrayList、Vector、LinkedList)
    Set:无序,不可重复(子类:HashSet、TreeSet)
    

    11Collection 和 Collections的区别

    Collection是集合类的上级接口,继承与他的接口主要有Set 和List.
    Collections是针对集合类的一个工具类,他提供一系列静态方法实现对各种集合的搜索、排序、线程安全化等操作。
        常用方法有:sort()排序、shuffle()打乱、reverse()反转
    Java中的工具类的命名习惯+s结尾
    

    12ArrayList,Vector,LinkedList的存储性能和特性是什么?

    ArrayList和Vector
    ArrayList 和Vector都是使用数组方式存储数据,
    此数组元素数大于实际存储的数据以便增加和插入元素,它们都允许直接按序号索引元素,
    但是插入元素要涉及数组元素移动等内存操作,所以索引数据快而插入数据慢,
    Vector由于使用了synchronized(锁)方法(线程安全),通常性能上较ArrayList差,
    ArrayList:线程不安全,效率高,常用
    Vector:线程安全的,效率低
    而LinkedList使用双向链表实现存储,按序号索引数据需要进行前向或后向遍历,但是插入数据时只需要记录本项的前后项即可,所以插入速度较快。
    

    13ArrayList和LinkedList的区别

    底层数据结构的差异:
        ArrayList:数组,连续一块内存空间,扩容是创建一个新数组长度为新数组的1.5倍(原数组定下来不变了)将原来的迁移过来
        LinkedList:双向链表,头尾都要加两个指针,内存空间更大点,不是连续的内存空间
    常规结论:
        ArrayList:查找快,因为是连续的内存空间,方便寻址,但删除插入慢,因为需要发生数据的迁移
        LinkedList:查找慢,因为需要通过指针一个个寻找,但删除插入块,因为只要改变前后节点的指针偏向
    

    14如何在双向链表A和B中插入C

    C.pre=A
    c.next=B
    A.next=C
    A.next.pre=C
    

    15.HashSet的存储原理

    HashSet底层采用的是HashMap来实现存储,其值作为HashMap的Key
    
    为什么采用Hash算法,有什么优势解决什么问题
    解决的问题是当我们往数组放数据时,如何判断是否唯一,传统方法时遍历
    
    存储原理
    object中有个hashcode方法,通过计算存储对象的hashcode,在于数组的长度-1做位运算,得到我们要存储在那个数组的坐标下,这样提高效率
    但是随着元素的不断添加,就可能出现哈希冲突,即不同对象计算出来的hash值相同
    这个时候才需要用到equals方法
    
    哈希表是一张什么表
    本质是一个数组,而数组的本质是链表
    在记录的存储位置和它的关键字之间建立一个确定的对应关系f,使每个关键字和结构中一个唯一的存储位置相对应。
    

    16.HashTable&HashMap&ConcurrentHashMap

    HashMap和Hashtable都实现了Map接口,三者在开发中的选择:HashMap>ConcurrentHashMap>hashtable
    
    HashTable
    线程安全的对象,内部有上锁的控制(synchronized),性能不高
    
    HashMap
    线程不安全对象,内部无上锁,put和get可以同时不会阻塞。
    优点:效率高
    缺点:如果有多个线程同时操作这一个hashmap,可能出现线程不安全,甚至是死锁(整个都锁住了)
    容量: 2^n是为了让散列更加均匀
    
    ConcurrentHashMap
    分段锁,将锁的力度变小,兼顾两者保证线程安全和性能,将原先的哈希表拆成好几段
    采用Segment + HashEntry的方式进行实现的,lock加在Segment上面。
    

    17.如何写一个栈stack

    1.数组
    2.先进后出
    3.出栈(取末尾的元素)
    4.入栈(默认加到末尾)
    

    18.IO流的分类及选择

    按方向分:输入流和输出流(站在程序的角度看)
    按读取的单位分:字节流(二进制文件)、字符流(文本文件)有BUffer缓冲区
    按处理的方式分:节点流、处理流
    IO流的4大基类:InputStream、OutputStream、Reader、Writer
    

    19.serialVersionUID的作用

    当执行序列化时,我们写对象到磁盘中,会根据当前这个类的结构生产一个版本号ID
    当反序列化是,程序会比较磁盘中的序列化版本ID跟当前类结构生成的版本号ID是否一致,一致的话则反序列化成功
    加上版本号,有助于我们的类结构发生变化时,依然可以与之前已经序列化的对象反序列化成功
    

    20.异常体系(保证健壮性)

    常见的五个运行时异常
    通常此类异常成为逻辑异常:
        算数异常
        空指针异常
        类型转换异常
        数组越界
        数字格式异常
    
    常见的五个非运行时异常
    IOException
    SQLException
    FileNotFoundException
    NoSuchFileException
    NoSuchMethodException
    

    21.Throw跟Throws的区别

    throw作用于方法内,用于主动的抛出异常
    throws作用于方法声明上,声明该方法有可能会抛出某些异常
    自定义异常一般继承RunnTimeException(运行期异常)
        框架:制定一系列规则,如果没按照规则做即是逻辑错误-->运行期异常
    

    22.创建线程的方式

    常用有三种方式:
        1.继承Thread
        2.实现Runable接口
        3.实现Callable接口(可以获取线程执行之后的返回值)
        本质上就是继承Thread,实现接口还需要通过创建Thread对象来实现,如new Thread(new Runnable(){}).start()
        在实际开发中,通常采用线程池的方式来完成Thread的创建。
            Thread:启动线程创建对象后,调用对象  .start
            接口:创建对象后, newThread(对象).start
        runable与callable 的区别是有无返回值的区别
    GC垃圾回收线程:后台线程
    

    23.线程安全问题

    当多个线程访问一个对象时,如果不用进行额外的同步控制或其他的协调操作
    调用这个对象的行为都可以得出正确结果,则就叫做线程安全
    比如:
        StringBuffer,我们多个线程在执行什么append等操作时,我们不需要加额外的控制如锁,就可以正常执行不发生错乱,这就是一个线程安全的对象
    如何做到线程安全:
        最常见的方式是:采用synchronized关键字给代码块或方法加锁,StringBuffer的源码就是这样
    
    如果在开发中需要拼接字符串,使用的是StringBuffer还是StringBuilder
    场景一:
        如果多个线程访问同一个资源,那么久需要上锁,保证数据的安全性。
        这个时候如果使用非线程安全的对象,比如StringBuilder,那么这个时候就得借助外力:如加synchronized关键字
    场景二:
        如果每个线程访问的是各自的资源,那么久无需考虑线程安全问题。
        这个时候就可以使用非线程安全对象StringBuilder
    总之,要先确定访问的资源是否是共享资源(成员变量),且该资源是有状态的,即数据会有变化。
    如果是就需要考虑线程安全问题
    

    24.Sleep和wait的区别

    1.所属类不同:
        sleep方法定义在Thread上
        wait方法定义在Object上
    2.对于锁资源的处理方式不同:
        sleep不会释放锁,抱着睡
        wait会释放锁
    3.使用范围:
        sleep可以使用在任意代码块
        wait必须在同步方法或同步代码块
    4.生命周期的状态:
        sleep会进入到time waiting状态
        wait会进入到waiting状态
    为什么wait在object里,而不定义在Thread上:
        在同步代码块中,我们需要一个对象锁来实现多线程的互斥效果
        也就是说,java锁是一个对象级别的,而不是线程级别的
        (sleep是线程休眠)
    为什么wait必须在同步代码块中使用:
        避免cpu切换到其他线程,而其他线程又提前执行了notify
        (就是还没生产就被消费了,然后之后就没人给唤醒了)
        所以需要一个同步锁来保护
    

    25.ThreadLocal的理解

    ThreadLocal作用:
       为每个线程创建一个副本 实现线程在上下文传递对象
    每个线程都有一个map
        key:thread     value:具体存放的东西
    
    ThreadLocal在实际开发中解决什么问题
    mybatis管理sqlsession,管理connection
    

    26.JDK类加载机制

    什么是类加载机制
    JVM在使用java类的程序为:
        1.Java源文件-->编译-->class文件
        2.类加载其ClassLoader读取这个类文件,并将其转换为java.lang.Class的实例
        有了该实例,JVM就可以使用他来创建对象、调用方法等操作
    
    Class文件的来源
    1.java自身内部的核心类:在jre/lib/rt.jar
    2.java的扩展类,位于jre/lib/ext目录
    3.我们自己开发的类或项目开发用到的第三方jar包
    
    JDK如何加载这些类
    针对不同来源,java分了不同的ClassLoader来加载
    1.核心类:Java运行的基础类,由一个BootstrapClassLoader的加载器负责实现。根加载器或引导加载器
    JVM内部实现对,java程序访问不到
    2.Java扩展类。是由ExtClassloader实现的,扩展类加载器
    3.项目编写的类,由appClassLoader实现,系统类加载器
    双亲委托机制
    

    27.Ajax的工作原理

    三个要素:异步交互,XMLHttpRequest对象,回调函数
    异步刷新,注册(用户名唯一)
    

    28.JavaScript原型机制

    javascript的原型有一个关键作用就是扩展其原有类的特性
    

    29.JSP和Servlet的区别

    技术的角度:
        JSP本质就是一个Servlet
        JSP的工作原理:JSP-->编译-->Servlet(java)-->编译-->class(最终跑的文件)
    应用的角度:
        JSP=HTML+Java
            <html>
                <%  java  %>
            </html>
        Servl=Java+HTML 
            out.write("<html>")
        jsp的特点在于实现视图,servlet的特点在于实现控制逻辑
        MVC模型
            M:模型
            V:视图      JSP
            C:控制器    Servlet
    

    30.Servlet的生命周期

    单实例的
    生命周期:
        创建对象-->初始化-->service()-->doXXX-->销毁
    创建对象的时机:
        1.默认是第一次访问该Servlet的时候创建
        2.也可以通过配置web.xml,来改变创建时机,比如容器启动的时候区创建
            DispatchServlet(springMVC前端控制器)
            <load-on-startup>1</load-on-startup>
    执行次数:
        对象的创建只有一次,单例
        初始化一次,销毁一次
    线程安全问题:
        构成线程不安全的因素:
            1.多线程环境(多个客户端,同时访问Servlet)
            2.多个线程共享资源,比如一个单例对象
            3.这个单例对象是有状态的
    

    31.Session跟Cookie的区别

    都有key-value结构
    1.存储位置不同:
        Session:服务器端
        Cookie:客户
    2.存储的数据格式不同:
        Session:value为对象,Object为类型
        Cookie:value为字符串,如果要存储一个对象,则需要将对象转为json
    3.存储数据的大小
        Session:受服务器限制
        Cookie:一般来说,最大为4k
    4.生命周期不同:
        Session:服务器端控制,默认30min,当用户关闭浏览器,session并不会小事
        Cookie:客户端控制,就是一个文件
            1.默认的是会话级的cookie,这种随着浏览器的关闭而关闭,比如保存sessionID的cookie
            2.非会话级的cookie,通过设置有效期来控制,比如"7天免登陆”设置:setMaxAge
    5.两者间的联系
        http协议是一种无状态协议,服务器为了记住用户的状态,采用的是Session的机制
        而Session机制背后的原理是,服务器会自动生成会话级的cookie来保存Session的标识
    

    32.转发和重定向的区别

    转发:
        发生在服务器内部的调转,对于客户端来说,至始至终就是一个请求,所以在这期间,保存在request对象中的数据可以传递
    重定向:
        发生在客户端的调转,是多次请求,如果需要在多次请求之间传递数据,需要调用session对象。
    

    33.谈谈三层架构

    web层:负责与用户交互并对外提供服务接口(springMVC,Struts2,Struts1)
    业务逻辑层:实现业务逻辑(spring)
    数据存取层:将业务逻辑层处理的结果持久化,方便后续查询(mybatis,Hibernate、springJDBC)
    

    34.谈谈对MVC的理解

    Model(模型)代表一个存取数据的对象或JAVA POJO
    View(视图)代表模型包含的数据的可视化比如HTML,JSP,FREEMAEKER
    Controller(控制器)控制器作用于模型和视图上,控制数据流向模型对象,并在数据变化时更新视图。
        如Servlet、Controller
    常见MVC框架:Struts1,Struts2.SpringMVC
    比如SpringMVC分为两个控制器
        DispatchServlet:前端控制器,由他来接收客户端的请求,
        在根据客户端请求的URL的特点,分发给对应的业务控制器(XXXController)
    

    35.jsp 9大内置对象

    内置对象:对于开发者自身无需创建,可以直接使用,因为内部已经帮我们创建了
    request-------HttpServletRequest
    response--------HttpServletResponse
    config---------ServletConfig
    application----ServletContext
    session
    exception
    page
    out
    pageContext
    

    36.JSP四大域对象

    ServletContext context域:只能在同一个web应用中使用(全局的)
    HttpSession session域:只能在同一个会话中使用
    HttpServletRequest request域:只能在同一个请求中使用
    PageContext page域:只能在当前的jsp页面使用
    

    37.并发和并行的区别

    并发:同一个CPU执行多个任务,按细分的时间片交替执行
    并行:再过个cpu上同时处理多个任务
    

    38.数据库设计的三大范式和反范式

    数据库的三大范式:
        第一范式:列不可分
        第二范式:要有主键
        第三范式:不可存在传递依赖(避免产生冗余信息)比如名字、地址、省份、城市这就有依赖,应该分开成名字、地址;地址、省份、城市
    反范式设计(第三范式)
    为什么:
        1.提高查询效率(读多写少)
        2.保存历史快照信息
    

    39.聚合函数

    聚合函数结合分组查询
    count()sum()avg()max()min()
    

    40.左连接、右连接、内连接,他们的区别是什么

    左连接:以左表为主
        select a.*,b.* from a left join b on a.b_id=b.id;
    右连接:以右表为主
    内连接:只列出两张表管理查询符合条件的记录
        select a.*,b.* from a inner join b on a.b_id=b_id
    区别:左右连接会一个表全出,然后连接另一个表符合条件的数据
    内连接就是符合两者条件的数据
    

    41.SQL注入

    是指通过字符串凭借的方式构成了一种特殊的查询语句,会错误的变成另一种条件的查询语句
    解决方案:
        预处理对象:采用PreparedStatement对象
        可以提高执行效率,因为是预先编译执行
    mybatis采用#解决
    

    42.JDBC如何实现对事务的控制及事务边界

    基于Connection进行控制
        connection.setAutoCommit(false)
        取消自动提交
    事务的边界放在业务层进行控制,因为业务层包含多个dao层的操作
    

    43.事务的特性

    简称ACID
        原子性(Atomicity)、一致性(Consistency)、隔离性(Isolation)、持久性(Durability)
    原子性是基础,隔离性是手段,一致性是约束条件,持久性是目的
    原子性:事务是数据库的逻辑工作单位,要么都成功要么都失败
    一致性:数据库中的数据在事务操作前后都必须满足业务规则约束
    隔离性:一个事务的执行不能被其他事务干扰。不同的隔离级别,互相干扰的程度不同
    持久性:事务一旦提交,结果就是永久性的。及时发生冗积,也可以依靠事务日志完成数据的持久化
    

    44.事务的隔离级别

    解决并发情况下,数据的安全性问题
    存在问题:
    	1. 脏读:一个事务,读取到另一个事务中没有提交的数据
    	2. 不可重复读(虚读):在同一个事务中,两次读取到的数据不一样。
    	3. 幻读:一个事务操作(DML)数据表中所有记录,另一个事务添加了一条数据,则第一个事务查询不到自己的修改。
     隔离级别:
    	1. read uncommitted:读未提交
    		* 产生的问题:脏读、不可重复读、幻读
    	2. read committed:读已提交 (Oracle)
    		* 产生的问题:不可重复读、幻读
    	3. repeatable read:可重复读 (MySQL默认)
    		* 产生的问题:幻读
    	4. serializable:串行化
    		* 可以解决所有的问题
    

    45.synchronized和lock的区别

    1.作用位置不同
        synchronized可以给方法,代码块加锁
        lock只能给代码块枷锁
    2.锁的获取锁和释放锁的机制不同
        synchronized无需手动获取锁和释放锁,发生异常会自动解锁,不会出现死锁
        lock需要自己枷锁和释放锁,如lock()和unlock(),如果忘记使用unlock会出现死锁
    synchronized修饰成员方法时,默认的锁对象,就是当前对象
    synchronized修饰静态方法时,默认的锁对象是当前类的class对象
    synchronized修饰代码块时,可以自己设置锁对象
    

    46.TCP和UDP的区别

    两者都是传输层协议
    TCP提供可靠的传输协议,传输时需要建立连接(三次握手),面向字节流,传输慢
    UDP无法保证传输的可靠性,无需创建连接,以报文的形式传输,效率高
    三次握手:
        1.客户端发送syn=随机数x给服务端要建立连接
        2.服务端反馈确认接收到请求发送syn ack=x+1 和随机数y 给客户端,告诉客户端准备好连接了
        3.客户端再向服务端发送ack=x+1,y+1。表示真的要建立连接
    四次挥手:
        1.客户端发生关闭连接指令:FIN=1 seq=random x
        2.服务端确认收到指令发送:ACK=1 ack=x+1 seq=random y。关闭服务端的输入流
        3.服务端也要关闭连接发送:FIN=1 seq=random z ack=ack+1。关闭服务端的输出流
        4.客户端确认收到消息,关闭连接:ACK=1 seq=x ack=z+1
    Http在应用层
    

    47.什么是死锁?如何防止?

    死锁就是线程A和线程B同时持有对方需要的锁,从而发生阻塞,最终变为死锁
    防止:
        尽量采用trylock方法,设置超时时间主动退出
        减少同步代码块的嵌套使用
        降低锁的使用粒度
    

    48.反射

    反射是一种能力,一种在程序运行时
        1.可以对任意一个类,动态获取当前类对象的所有属性和方法的能力,
        2.对于任意一个对象,都可以调用他的任意一个方法和属性
    可以动态执行方法,给属性赋值等操作的能力
    class代表的就是所有字节码对象的抽象类
    Class.forName()
    一个类的组成部分有哪些:
        1.属性
        2.方法
        3.构造方法
        4.接口
        5.注解
    在许多框架中都采用了反射的机制来实现动态效果
    比如@Autowrite就能实现自动注入
        注解的解析程序会扫描当前的包下有哪些属性加了这个注解,一旦有注解
        就会去容器里面获取对于的类型的实现,然后给这个属性赋值(这就是反射机制)
    

    49.SpringIOC的知识

    SpringIOC的理解
    是一种设计思想模式
    在平时的java应用开发中,我们要实现某一个功能或者说是完成某个业务逻辑时至少需要两个或以上的对象来协作完成,
    在没有使用Spring的时候,每个对象在需要使用他的合作对象时,自己均要使用像new object() 这样的语法来将合作对象创建出来,这个合作对象是由自己主动创建出来的,
    创建合作对象的主动权在自己手上,自己需要哪个合作对象,就主动去创建,创建合作对象的主动权和创建时机是由自己把控的,
    而这样就会使得对象间的耦合度高了,A对象需要使用合作对象B来共同完成一件事,A要使用B,那么A就对B产生了依赖,也就是A和B之间存在一种耦合关系,并且是紧密耦合在一起,
    而使用了Spring之后就不一样了,创建合作对象B的工作是由Spring来做的,Spring创建好B对象,然后存储到一个容器里面,
    当A对象需要使用B对象时,Spring就从存放对象的那个容器里面取出A要使用的那个B对象,然后交给A对象使用,
    至于Spring是如何创建那个对象,以及什么时候创建好对象的,A对象不需要关心这些细节问题(你是什么时候生的,怎么生出来的我可不关心,能帮我干活就行),A得到Spring给我们的对象之后,两个人一起协作完成要完成的工作即可。
    所以控制反转IoC(Inversion of Control)是说创建对象的控制权进行转移,
    以前创建对象的主动权和创建时机是由自己把控的,而现在这种权力转移到第三方,比如转移交给了IoC容器BEAN,
    它就是一个专门用来创建对象的工厂,你要什么对象,它就给你什么对象,有了IoC容器,依赖关系就变了,原先的依赖关系就没了,它们都依赖IoC容器了,通过IoC容器来建立它们之间的关系。
    
    SpringIOC的运用场景
    在应用开发中,当我们在设计组件时,往往需要引入和调用其他组件的服务时,
    这种依赖关系如果固化在组件设计中就会导致组件之间的耦合和维护难度的增大,
    这个时候如果使用 IoC 容器,把资源获取的方式反转,让 IoC 容器主动管理这些依赖关系,
    将依赖关系注入到组件中,那么这些依赖关系的适配和管理就会更加灵活。
    
    IOC容器如何实现
    使用方式:
        1.配置文件的方式
            <bean>
        2.注解的方式
            @Autowrite
    完成两个事情:
        1.解析2.实现复制
    配置方式:
            1.解析ML--》Dom4j
            2.调用方法实现注入
    注解方式:
            1.解析类:这个类归Spring管理,获取到该类的注解信息和属性的注解信息(反射)
            2.赋值
    

    50.Spring的bean作用域有哪些

    应用程序的主体及由SpringIoC容器所管理的对象,被称之为bean
    1.默认是singleton,即单例模式
    2.prototype,每次从容器调用bean时都会创建一个对象
    3.request,每次http请求就创建一个对象
    4.session,同一个session共享一个对象
    5.global-session
    

    51.Spring的bean是线程安全的嘛

    bean模式是单例的,是后端程序必然处于多个线程的工作环境下
    但是bean基本是无状态的,所以从这个点来说是安全的
    无状态就是没有存储数据
    

    52.什么是事物的传播特性,Spring支持的特性有哪些

    我们一般将事物的边界设置在service层
    当我们调用service层的一个方法时,它能够保证我们的这个方法中执行的所有对数据库的更新操作保持在一个事务中
    要么一起成功要么一起失败
    如果在调用service层中的多个service方法,那么这个事务如何规定,才能使得其为同一个事务,这就是事务传播特性
    spring支持的传播特性:
        PROPGATION_REQUIRED :支持当前事务,如果当前没有事务,就创建一个(默认的)
        PROPGATION_MANDATORY:支持当前事务,如果没有,就抛出异常
        PROPGATION_REQUIRES_NEW:新建事务,如果当前存在就给她挂起
        PROPGATION_NOT_SUPPORTED:以非事务方式操作
        PROPGATION_NEVER:以非事务方式操作,如果存在事务抛异常
    

    53.什么是悲观锁,什么是乐观锁

    悲观锁:
    每次去拿数据的时候都认为别人会修改,所以每次在拿数据的时候都会上锁,这样别人想拿这个数据就会阻止,直到这个锁被释放。
    利用数据库本身的锁机制来实现,会锁记录
        实现方式:select *from table where id = 1 for update
    乐观锁:
    每次去拿数据的时候都认为别人不会修改,所以不会上锁,但是在提交更新的时候会判断一下在此期间别人有没有去更新这个数据。
    数据库的乐观锁需要自己实现,是一种不锁记录的实现方式,采用CAS(compare and set)模式,建议采用version字段作为判断依据
    update t set store=store+1,version=version+1 where id=1 and version=old_version
    每次对数据更新操作,都会对version+1,这样提交更新操作时,如果version已被更改就操作失败
        为什么使用version字段
            如果选择其他字段,如业务字段store,那么可能会出现ABA问题(初始时A但是在过程中出现了B用B操作了数据,但是结束时又是用A,这样操作就有问题)
    优缺点:
    乐观锁:性能高、重试失败成本不高建议乐观
    悲观锁:性能低,但安全,失败成本高建议悲观,使用不当有死锁风险
    

    54.Mybatis的缓存机制

    缓存主要作用是提高查询的性能,减少跟数据库交互的次数,从而减轻数据库的承受压力
    适用于多读少写的常见,若数据变化频率高不适应
    mybatis的缓存分为一级缓存和二级缓存
        一级缓存:
            1.一级缓存模式是开启状态
            2.一级缓存作用域在sqlsession
            3.如果中间有对数据的更新操作,则清空一级缓存
        二级缓存:
            使用:
                1.开启二级缓存
                    <setting name="cacheEnabled"value="true"/>
                2.在mapper.xml中配置二级缓存
                    在<mapper>下面添加<cache/>标签
            默认的二级缓存的特点:
                1.所有的select语句会被缓存
                2.所有的更新语句将会刷新保存
                3.缓存将采用LRU算法来回收
                4.缓存会存储1024个对象的引用
                回收算法建议采用LRU
    

    55.MyBatis分页方式

    分为逻辑分页和物理分页
    逻辑分页:就是一次性查出多条数据,然后在检索分页中的数据,具体一次性查询几条由JDBC配置的fetch-size决定
    物理分页:从数据库中取出指定条数进行查询,我们所用的分页插件pageHelper实现的就是物理分页
    

    56.请求到响应经历了什么

    浏览器:
        1.检查输入的UOL格式是否正确
        2.解析域名、端口、路径
        3.检查当前有没有缓存,如果有,就直接使用缓存
        4.如果没有发起请求
        DNS:域名--->ip
    网络是分层的:TCP/IP协议
        应用层:http协议
        传输层:TCP协议(三次握手,四次挥手)
        网络层:IP-->MAC物理地址
        数据链路层:MAC
    到服务器反向解析
    

    57.synchronized的底层原理

    同步代码块:synchronized(){
    自动上锁--------monitorenyer
    自动解锁-------monitorexit
    }
    monitor的实现方式:偏向锁、轻量锁和重量锁
    锁会根据情况逐步升级到轻量锁和重量锁级别。这就是锁升级
    偏向锁和轻量锁为用户态,重量锁为内核态
    任何锁对象中都有一个Object字段叫threadID,默认情况为空
    当第一次有线程访问时,则该threadid设置为当前线程的id,这个为偏向锁,当线程执行结束后,重新置空
    之后线程再次进入时,会判断threadid是否与该线程一致,如果一致,则可以获取该对象,不一致就会发生锁升级,从偏向锁升级为轻量锁
    轻量锁的工作模式是通过自选循环的方式来获取锁,看对方的线程是否已经释放了锁,如果执行一定次数之后,还没有获取到锁,则发生锁升级,升级为重量锁
    synchronized如何保证可见性的:
        可见性原理:
            两个线程如何保证变量信息的共享可见性?
                线程A--》本地内存A(共享变量副本)--》主内存(共享变量)
                如果有变更,则需将本地内存的变量写到主内存,对方才可以获取到更新
        synchronized就是当获取到锁之后,每次读取都是从内存读取
        当释放锁的时候,都会将本地内存的信息写到主内存,从而实现可见 
    

    58.synchronized和volatile的区别

    作用的位置不同:
        synchronized是修饰方法和代码块
        volatile(没有上锁)是修饰变量的
    作用不同:
        synchronized:可以保证修改的可见性及原子(要么完整执行,要么完整失败)性,但可能会造成线程堵塞
        volatile:仅能实现变量修改的可见性,无法保证原子性,但不会造成线程堵塞
    

    59.公司采用什么样的开发模式?前后端如何对接

    前后端分离的模式,后端负责接口开发
    接口文档(1.URL,2.请求方式3.请求参数4.返回参数5.实例)
    一般才有swagger生成接口文档
    团队的配比:职能模式,产品维度
    

    初学者,欢迎指正!!

    展开全文
  • 什么是系统架构(Architecture) ...常见的架构模式有哪些?跟着 【码哥字节】了解不同的架构设计所运用的不同设计哲学。 一起来看下常见的架构模式:Client-Server、Peer to Peer、MVC、Layered、Distri
  • 你觉得目前市场上还有哪些领域可以应用我们的产品 eg 人工智能领域 智能排版(论文) 文本分析(自动思维导图) 文本压缩和扩展 eg物联网 你觉得to B的产品和to C的产品什么区别?to B的产品经理和to C的产品经理...
  • 12.23面试

    2016-12-23 17:05:14
    有哪些设计模式 手写单例模式 有哪些排序方法 手写冒泡法排序 手写链表逆序 思维题怎么把一个数组中的数分正负两列,他问的不对啊….他问的是分正负两列,但讲解的是指针分别指向头和尾然后数据判断。。。 ...
  • Java SE学习感想

    2020-07-29 18:12:15
    2.常见的代码思维模式有哪些? 面向过程,面向对象,面向接口,函数式编程等等 3.面向对象是什么? 编程, 在我理解而言,面向对象其实就是面向抽象编程. 4.什么是抽象? 抽象可以理解成抽离不同事物之间的共性,抽离出的这个...
  • 程序员可以选择哪些平台写技术博客? IDEA使用总结 Maven就是这么简单 敖丙这逼竟然连Maven都不会 SVN就是这么简单 UML就是这么简单 听说新版IDEA支持中文,三歪体验了一把 加入公众号 精美脑图、学习路线、1000+...
  • C++程序员面试宝典

    热门讨论 2013-04-01 13:36:19
    面试题101 成员变量有哪些访问控制方式 105 面试题102 如何访问静态成员 106 9.4 多态 108 面试题103 什么是多态?多态的作用 108 面试题104 在C++中如何实现多态 109 第10章 继承(教学视频:44分钟) 113 10.1 ...
  • 鉴于此,本书除了对传统的计算机相关知识(Java语言基础知识、Web基础知识、数据结构与算法、数据库、设计模式等)以及面试笔试真题进行分析与解答外,还根据当前计算机技术的发展潮流,对面试笔试中常见的海量数据...
  • 学Java有哪些热门就业方向? 安卓开发 Java 后端开发 大数据/数据仓库 Java基础 学什么? 怎么学? 视频学习 精选书籍推荐 面试系列 Java进阶 学什么? 怎么学? 精选书籍推荐 Java注解 Java8实战...
  • 说实话我自己当初在这方面吃了不少亏,很多比较好的习惯我也是后面自己才慢慢发现,所以这里想着重给大家说一下有哪些好的学习和编程习惯。 正确提问 我们平时任何时候都离不开提问特别是初学的时候,但是真正知道...
  • 这里一张互联网公司面试中经常考察的问题类型总结的思维导图,我们可以结合图片中的信息分析一下。 (图片来自 leetcode) 其中算法,主要是以下几种: 基础技巧:分治、二分、贪心 排序算法:快速排序、归并...
  • 《Effective c++ 》

    千次下载 热门讨论 2013-02-25 22:13:11
    C++ 的难学,不仅在其广博的语法,以及语法背后的语义,以及语义背后的深层思维,以及深层思维背后的对象模型;C++ 的难学还在于它提供了四种不同而又相辅相成的编程范型(programming paradigms):procedural-...
  • DBA最重要的素质有哪些 11 DBA职业生涯之误删除篇 12 DBA警世录——有些习惯DBA需要养成 13 RAC环境下故障处理一则 14 SQL_TRACE跟踪与诊断 16 临时表空间组导致递归SQL高度解析案例 19 使用闪回查询恢复误...
  • CruiseYoung提供的带详细书签的电子书籍目录 http://blog.csdn.net/fksec/article/details/7888251 Oracle SQL高级编程(资深Oracle专家力作,OakTable团队推荐) 基本信息 原书名: Pro Oracle SQL 原出版社: ...
  • CruiseYoung提供的带详细书签的电子书籍目录 http://blog.csdn.net/fksec/article/details/7888251 该资料是《Oracle SQL高级编程》的源代码 对应的书籍资料见: Oracle SQL高级编程(资深Oracle专家力作,...
  • iPhone开发秘籍(第2版)--源代码

    热门讨论 2012-12-11 13:51:22
    7.16 补充内容:灰度模式 236 7.17 小结 237 第8章 手势和触摸 238 8.1 触摸 238 8.1.1 阶段 238 8.1.2 触摸和视图方法 239 8.1.3 触摸视图 239 8.1.4 多点触摸 240 8.2 秘诀:添加一个简单直观的操作界面 ...
  • front-end-Doc ...不要带着jQuery的思维去学习AngularJS http://www.rainweb.cn/article/angularjs-jquery.html angularjs 学习笔记 http://wangjiatao.diandian.com/?tag=angularjs angularjs 开发指南 ...

空空如也

空空如也

1 2
收藏数 21
精华内容 8
关键字:

常见思维模式有哪些