面试JAVA

2018-09-16 JAVA设计模式

2018-09-19  本文已影响11人  闭门造折

主要参考资料:《Java开发中的23种设计模式详解》

一、三大分类

详细的分类模式可能不太好记,建议先知道三种分类,然后跳过这块继续阅读。

  1. 创建型模式:主要用于处理对象的创建,实例化对象。
    主要有:工厂模式、单例模式、建造者模式、原型模式
  2. 结构型模式:处理类和对象间组合。
    主要有:适配器模式、装饰器模式、代理模式、外观模式、桥接模式、组合模式、享元模式
  3. 行为型模式:描述类和对象怎么交互或分工。
    主要有:策略模式、模板方法模式、观察者模式、迭代子模式、责任链模式、命令模式、备忘录模式、状态模式、访问者模式、中介者模式、解释器模式

参考资料:《设计模式——怎么就给分成三类了呢?》

二、六大原则

1. 开闭原则

对扩展开放,对修改关闭。即想实现新功能的时候,提供接口,但是不能对源代码做修改。

2. 里氏代换原则

一种规范,任何基类可以出现的地方,子类一定可以出现。这样才能确保衍生类替换基类的时候,不会出错。

3. 依赖倒转原则

针对接口编程,依赖于抽象,而不依赖具体

4. 接口隔离原则

参考资料《Java开发中的23种设计模式详解》中写,这个原则就是使用多个隔离的接口,比使用单一接口要好。但是我不理解什么是隔离的接口。
继续查资料,参考资料《六大设计原则之接口隔离原则》有另两种解释:
4.1 客户端不应该依赖他不需要的接口
4.2 类间依赖关系应该建立在最小的接口上
合起来就是减少臃肿庞大的接口,接口细化

5. 迪米特法则(最少知道原则)

一个实体应当尽量少的与其他实体发生相互作用,使得系统功能模块相对独立。

6. 合成复用原则

更多的使用合成/聚合的方式,而不是继承。

三、具体模式

以下为创建型模式

1. 普通工厂模式

定义创建对象的接口,实例化的时候,通过传入内容,实例化不同类。

接口:
public interface Sender(){
    void Send();
}

实现类1(邮件发送):
public class MailSender implements Sender(){
    @Override
    public void Send(){
        System.out.println("this is mail sender");
    }
}
实现类2(邮包发送):
public class BoxSender implements Sender(){
    @Override
    public void Send(){
        System.out.println("this is box sender");
    }
}

工厂类:
public class SendFactory{
    public Sender produce(String type){
        if("mail".equals(type)){
            return new MailSender();
        }
        else if("box".equals(type)){
            return new BoxSender();
        }
        else{
            System.out.println("类型错误");
            return null;
        }
    }
}
2. 多个工厂方法模式

实际上就是将上个模式中的工厂类中的判别,改为不同的方法,实例化的时候调用不同方法,创建不同实例化对象。

public class SendFactory{
    public Sender produceMail(){
        return new MailSender();
    }

    public Sender produceBox(){
        return new BoxSender();
    }
}
3. 静态工厂方法模式

在多个工厂方法模式的基础上,把工厂类中所有的子创建方法,改为static,也即是不需要特意创建工厂类的实例化对象,可以直接调用得到创建方法。

4. 抽象工厂类

为了可扩展性,拆分工厂类

工厂类接口
public interface Provider{
    public Sender produce();
}
第一个工厂类
public class SendMailFactory implements Provider(){
    @Override
    public Sender produce(){
        return new MailSender();
    }
}
第二个工厂类
public class SendBoxFactory implements Provider(){
    @Override
    public Sender produce(){
        return new BoxSender();
    }
}
main函数:
public static main(String[] args){
    Provider provider = new SendMailFactory();
    //实例化工厂类对象
    Sender sender = provider,produce();
    //得到实例化对象产生的Sender对象
    sender.Send();
}
5. 单例模式

计划生育,让一个类仅拥有一个实例化对象

public class Singleton{
    private static Singleton intance = null;
    
    private Singleton(){
    }
    
    public static Singleton getInstance(){
        if(interface == null){
            //为空则实例化
            instance = new Singleton();
        }
        return instance;
    }

    public Object readResolve(){
        return instance;
    }
}
6. 建造者模式

创建复合对象,其实建造者模式就是将抽象工厂模式利用起来。
工厂模式是为了创建好单个对象
建造者模式则是为了创建复合对象

建造者类:
public class Builder{
    private List<Sender> list = new ArrayList <Sender>();
    //一个类内公有的私有对象
    public void produceMailSender(int count){
        for(int i = 0; i < count; i++){
            list.add(new MailSender());
        }
    }
    public void produceBoxSender(int count){
        for(int i = 0; i < count; i++){
            list.add(new BoxSender());
        }
    }
}
调用的时候交替调用两个方法,即可得到一个重复交替的list队列
7. 原型模式

利用原型,来克隆产生新的对象

public class Prototype implements Cloneable{
    public Object clone throws CloneNotSupportedException{
        //浅复制
        Prototype proto = (Prototype) super.clone();
        return proto;
    }
    public Object deepClone() throws IOException, ClassNotFoundException{
        //深复制
        //写入当前对象二进制流
        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        ObjectOutputStream oos = new ObjectOutputStream(bos);
        //向bos中写入this的内容
        oos.writeObject(this);

        //读出当前对象二进制流
        ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
        ObjectInputStream ois = new ObjectInputStream(bis);

        return ois.readObject();
    }
}

以下为结构型模式

8. 类的适配器模式

想把一个类,转换成满足一个新接口的类时,可以用类的适配器模式,创建一个新类,继承原来的类,并实现新的接口。

原有的类:
public class Source{
    public void method_old(){
        System.out.println("this is an old method");
    }
}
新的接口:
public interface TargetInterface{
    public void method_old();
    public void method_new();
}
通过新的类实现:
public class Adapter extends Source implements TargetInterface{
    @Override
    public void method_new(){
        System.out.println("this is a new method");
    }
}
9. 对象的适配器模式

不再继承原有类,而是改为存储原有类实例化对象。

新的类:
public class Adapter implements TargetInterface{
    private Source source;
  
    public Adapter(Source source){
        super();
        this.source = source;
    }

    @Override
    public void method_new(){
        //新方法仍需要手动实现
        System.out.println("this is a new method");
    }

    @Override
    public void method_old(){
        source.method_old();
    }
}
10. 接口的适配器模式

interface里面要求的方法太多了,但是不是所有的方法都是我们所需要的。使用抽象类实现所有接口,这样我们的具体类实现的时候,可以调用抽象类,并只实现其中部分接口就行了。

原有的interface:
public interface Sourceable{
    public void garbage_method1();
    public void garbage_method2();
    public void method3();
    public void method4();
}
通过抽象类,假装“实现”四种方法
public abstract class Wrapper implements Sourceable{
    public void garbage_method1(){}
    public void garbage_method2(){}
    public void method3(){}
    public void method4(){}
}
当我们真的需要实现某个类的时候,只需要实现想实现的方法,并继承抽象类就行了
public class Source extends Wrapper{
    public void method3(){
        System.out.println("the useful method");
    }
}
11. 装饰模式

给一个对象增加一些新的功能

接口需求
public interface Sourceable{
    public void method();
}
原有类
public class Source implements Sourceable{
    @Override
    public void method(){
        System.out.println("the original method!");
    }
}
装饰类
public class Decorator implements Sourceable{
    private Sourceable source;

    public Decorator(Sourable source){
        super();
        this.source = source;
    }
    @Override
    public void method(){
        "do something there"
        source.method();
        "do something there"
    }
}
12. 代理模式

和装饰模式非常像,唯一的差别是,装饰模式中,source是传入的参数。而代理模式中,source是new出来的对象。即代理模式中,不需要提前创建好要改进的类,直接调用代理模式的类即可。

public Proxy(){
    super();
    this.source = new Source();
}
13. 外观模式

多个类,不想让他们产生交流和关系。通过一个类统一调度,降低类类之间耦合度。

三个不想让他们产生关联的类CPU Memory和Disk
public class CPU{
    public void startup(){
        System.out.println("cpu start up!");
    }
    public void shutdown(){
        System.out.println("cpu shut down!");
    }
}
public class Memory{
    public void startup(){
        System.out.println("memory start up!");
    }
    public void shutdown(){
        System.out.println("memory shut down!");
    }
}
public class Disk{
    public void startup(){
        System.out.println("disk start up");
    }
    public void shutdown(){
        System.out.println("disk shut down");
    }
}
用外观模式,做一个统一调度类
public class Computer{
    private CPU cpu;
    private Memory memory;
    private Disk disk;

    public Computer(){
        cpu = new CPU();
        memory = new Memory();
        disk = new Disk();
    }

    public startup(){
        cpu.startup();
        memory.startup();
        disk.startup();
    }
}
14. 桥接模式

不想直接通过实例化对象.方法()的方式调用。
不知道有什么用处,下方的例子中,先后实例化Source1和Source2,传入MyBridge中调用method方法,输出两个提示信息。

接口设置
public interface Sourceable{
    public void method();
}
两个实现类
public class Source1 implements Sourceable{
    @Override
    public void method(){
        System.out.println("随便打点什么反正也不会运行我是第一个实现类");
    }
}
public class Source2 implements Sourceable{
    @Override
    public void method(){
        System.out.println("我是第二个实现类");
    }
}
定义一个虚类,来持有一个Source对象
public abstract class Bridge{
    private Sourceable source;
    
    public void setSource(Sourceable source){
        this.source = source;
    }
    public Sourceable getSource(){
        return this.source;
    }
}
定义一个具体实现的类,继承虚类,不然不能实例化
public class MyBridge() extends Bridge{
    public void method(){
        getSource().method();
    }
}
15. 组合模式

通常用来表示树等结构
举例:类中含有属性:子节点列表,父节点,权值,节点命名等

16. 享元模式

通常与工厂模式组合使用。如果某对象已存在,直接返回该对象,否则,新建一个对象。

以下为行为型模式

17. 策略模式

定义一系列算法,可以互相替换。可以定义一个接口类,规定要实现的统一方法。
策略模式通常使用于算法决策系统,用户只需要选择使用哪个算法即可。

接口
public interface Rule{
    public void calcu();
}
三个实现类
public class Plus implements Rule{
    @Override
    public void calcu(){
        System.out.println("+");
    }
}
public class Sub implements Rule{
    @Override
    public void calcu(){
        System.out.println("-");
    }
}
public class Mul implements Rule{
    @Override
    public void calcu(){
        System.out.println("*");
    }
}
18. 模板方法模式

定义一个抽象类,子类继承抽象类。实例化的时候采用
抽象类类名 tmp = new 子类名();
的方法调用。感觉是为了加深子类调用的理解。

19. 观察者模式

当一个类发生变化的时候,其他依赖该对象的对象会受到通知。就像是我关注了你,你发了个段子,我立刻就会收到消息。

随意的接口
public interface Observer{
    public void update();
}
两个实现类
public class Observer1 implements Observer{
    public void update(){
        System.out.println("骗你的,其实根本不更新");
    }
}
public class Observer2 implements Observer{
    public void update(){
        System.out.println("我也是骗你的");
    }
}
监控器虚类
public abstract class AbstractSubject{
    private Vector<Observer> vector = new Vector<Observer>();
    public void add(Observer observer){
        vector.add(observer);
    }
    public void del(Observer observer){
        vector.remove(observer);
    }
    修改预警:
    public void notifyObserver(){
        Enumeration<Observer> enumo = vector.elements();
    while(enumo.hasMoreElements()){
        enumo.nextElement().update();
    }
    }
}
20. 迭代器模式

用类来实现迭代器的功能

21. 责任链模式

用类来实现链表的功能

22. 命令模式

实现命令发出者和执行者之间的解耦。实现请求和执行分开。
指令(interface) - 指令调度器(实现指令功能,持有执行者对象) - 执行者

23.备忘录模式

同另一个类,存储当前类的所有有价值信息,不做修改等处理,只做get set操作

24. 状态模式

类似于QQ隐身、在线、忙碌的状态切换,不同状态会改变其行为。

25. 访问者模式

外部传入访问者对象

接口
public interface Visitor{
    public void visit(Subject sub);
}
访问类
public class MyVisitor implements Visitor{
    public void visit(Subject sub){
        System.out.println("The visitor is:" + sub.getName());
    }
}
接受访问的类的接口
public interface Subject{
    public void accept(Visitor visitor);
    public String getName();
}
接受访问的类的实现
public class MySubject implements Subject{
    public void accept(Visitor visitor){
        visitor.visit(this);
    }
    public String getName(){
        return "LiuDehua";
    }
}
测试类:
public class Test{
    public static void main(String[] args){
        Visitor visitor = new MyVisitor();
        Subject sub = new MySubject();
        sub.accept(visitor);
    }
}
输出结果
The visitor is:LiuDehua
26. 中介者模式

两个类存在关系,又不想让他们彼此持有实例化对象,采用中介者调度。
感觉类似于13 外观模式

27. 解释器模式

就是用来解释说明各种各样的类
给定一个语言,定义他的文法的一种表示,并定义一个解释器,这个解释起使用该表示解释语言中的句子。
一般用来存文法中终结符对应的具体值
比如R=R1+R2,R1=100,R2=200;
那么R1,R2,R的解释结果依次是100,200,300
参考资料 《设计模式之笔记--解释器模式(Interpreter)》

上一篇下一篇

猜你喜欢

热点阅读