深入浅出设计模式,跟着思路快速理解

简介: 设计模式目的是为了代码可重用,降低代码的耦合度,提高代码的可扩展性、可维护性,不可为了使用设计模式而过度设计,要平衡复杂度和灵活性。

前言

设计模式目的是为了代码可重用,降低代码的耦合度,提高代码的可扩展性、可维护性,不可为了使用设计模式而过度设计,要平衡复杂度和灵活性。

设计原则

设计模式一般需要符合以下几个原则:

开闭原则

开放扩展,关闭修改。简单来说,在添加新功能时能不修改就不修改,通过新增代码可以实现那是最好的。

里氏替换原则

一种面向对象的设计原则。简单来说,一个方法如果可以通过父类调用成功,那么替换成子类调用也可以成功。

单一职责

一个类只负责一个功能领域中相应的职责。

迪米特法则

最少知道原则,不希望类之间建立直接联系,降低耦合度,如果真的需要希望通过中介通信。

设计模式

目前常见的设计模式分为以下3个类型:

创建型模式

封装了系统中对象如何创建、组合等信息。重点关注如何创建对象,将对象的创建和使用分离。

工厂方法

通过工厂生产的形式获取对象,客户端引用抽象工厂及抽象产品,不关注如何创建。
应用案例:Spring的BeanFactory
代码示例:

//工厂类
public interface IFactory {
   
    IProduct create();
}
//具体工厂实现
public class FactoryA implements IFactory{
   
    @Override
    public IProduct create() {
   
        return new ProductA();
    }
}
// 产品抽象类
public interface IProduct {
   
    void get();
}
//具体产品实现
public class ProductA implements IProduct{
   
    @Override
    public void get() {
   }
}
public class FactoryMain {
   
    public static void main(String[] args) {
   
        IFactory factory=new FactoryA();
        IProduct product=factory.create();
        product.get();
    }
}

抽象工厂

基于工厂方法,在工厂中生产多个产品,也是与其的区别。
代码示例:

//抽象工厂类
public interface IFactory {
   
//抽象工厂中多个产品或产品组
    IProductA createA();
    IProductB createB();
}
//抽象工厂具体实现
public class FactoryA implements IFactory {
   
//抽象工厂具体产品指向
    @Override
    public IProductA createA() {
   
        return new ProductA();
    }

    @Override
    public IProductB createB() {
   
        return new ProductB();
    }
}
//产品或产品组A
public interface IProductA {
   
    void get();
}
//产品或产品组B
public interface IProductB {
   
    void get();
}
//产品或产品组A具体实现
public class ProductA implements IProductA{
   
    @Override
    public void get() {
   }
}
//产品或产品组B具体实现
public class ProductB implements IProductB{
   
    @Override
    public void get() {
   }
}
public class FactoryMain {
   
    public static void main(String[] args) {
   
        // FactoryA 工厂下的 IProductA和IProductB
        IFactory factoryA=new FactoryA();
        IProductA AproductA=factoryA.createA();
        AproductA.get();
        IProductB AproductB=factoryA.createB();
        AproductB.get();
    }
}

单例

保证一个类只有一个实例,并提供全局访问。
应用案例:Spring的SingletonBeanRegistry
代码示例:

public class SingletenInstance {
   
    public static final SingletenInstance instance=new SingletenInstance();
    private SingletenInstance(){
   };
    public static void main(String[] args) {
   
        SingletenInstance instance1=SingletenInstance.instance;
        SingletenInstance instance2=SingletenInstance.instance;
        System.out.println(instance1==instance2);//true
    }
}

原型

创建对象时根据现有的对象创建。
应用案例:java的Object提供的clone()方法
代码示例:

public class PrototypeObj implements Cloneable{
   
    @Override
    protected PrototypeObj clone() throws CloneNotSupportedException {
   
        return new PrototypeObj();
    }
    public static void main(String[] args) throws CloneNotSupportedException {
   
        PrototypeObj obj1=new PrototypeObj();
        PrototypeObj obj2=obj1.clone();
    }
}

建造者(生成器)

将复杂对象的构建过程抽象出来,通过不同的实现构造不同表现的对象。
应用场景:StringBuilder
代码示例:

public class BuilderObj {
   
    private String attr1;
    private String attr2;
    private String attr3;


    public BuilderObj build() {
   
        return this;
    }

    public BuilderObj setAttr1(String attr1) {
   
        this.attr1 = attr1;
        return this;
    }

    public BuilderObj setAttr2(String attr2) {
   
        this.attr2 = attr2;
        return this;
    }

    public BuilderObj setAttr3(String attr3) {
   
        this.attr3 = attr3;
        return this;
    }
    public static void main(String[] args) {
   
        BuilderObj obj = new BuilderObj().setAttr1("Attr1").setAttr3("Attr3").build();
    }
}

结构型模式

如何组合己有的类和对象以获得更大的结构。重点关注如何组合对象,通过组合对象灵活使用获得更好、更灵活的结构。

适配器

将一个接口转换成提供者需要的接口,通过对接口的转换使得两个本来不兼容的接口可以一起工作。
应用案例:ExecutorService对Callable及Runnable的兼容
代码示例:

public class RunnableAdapter implements Runnable{
   
    private Callable callable;
    //适配Callable接口
    public RunnableAdapter(Callable callable) {
   
        this.callable=callable;
    }

    @Override
    public void run() {
   
        try {
   
            System.out.println(callable.call());
        } catch (Exception e) {
   
            e.printStackTrace();
        }
    }
    public static void main(String[] args) {
   
        Callable callable =()->"I'm call";
        new Thread(new RunnableAdapter(callable)).start();
    }
}

装饰器

简单来说,动态给对象添加一些额外的功能。
应用案例:FilterInputStream就属于一个装饰类,其继承InputStream,所有InputStream可以通过FilterInputStream下面的类进行装饰获取额外功能,比如通过BufferedInputStream缓冲功能提高读取效率、通过DataInputStream读数据时可以直接转换java基本类型等。
代码示例:

public interface Keyboard {
   
    public void print();
}
public class KeyboardNormal implements Keyboard{
   
    public void print(){
   
        System.out.println("按键");
    }
}
public class KeyboardLight implements Keyboard{
   
    private Keyboard keyboard;
    //装饰对象
    public KeyboardLight(Keyboard keyboard) {
   
        this.keyboard=keyboard;
    }

    public void print(){
   
        this.keyboard.print();
        System.out.println("闪光效果");
    }
}
public class KeyboardVoice implements Keyboard{
   

    private Keyboard keyboard;
    //装饰对象
    public KeyboardVoice(Keyboard keyboard) {
   
        this.keyboard=keyboard;
    }

    public void print(){
   
        this.keyboard.print();
        System.out.println("声音效果");
    }
}
    public static void main(String[] args) {
   
        Keyboard keyboardNormal=new KeyboardNormal();
        //装饰对象灯光效果
        Keyboard keyboardLight=new KeyboardLight(keyboardNormal);
        //装饰对象声音效果
        Keyboard keyboardVoice=new KeyboardVoice(keyboardLight);
        keyboardVoice.print();
        //按键
        //闪光效果
        //声音效果
    }

享元

核心思想是共享,如果一个对象一经创建很少变动,那直接返回共享实例即可(重复利用对象)。
应用案例:可以看下Integer.valueOf(),在初始化数据时如果是-128~127就直接返回数据。线程池等。
代码示例:

public class FlyWeightObj {
   
    String cache = "value";
    public String get() {
   
        if (null != cache) {
   
            return cache;
        }
        return new String("chche");
    }
}

代理

通过一个代理对象控制一个对象的访问,和适配器模式相似,不过是同一接口。
应用案例:Spring AOP
代码示例:

public class RunnableProxy implements Runnable{
   

    private Runnable runnable;
    //代理Runnable对象
    public RunnableProxy(Runnable runnable) {
   
        this.runnable=runnable;
    }

    @Override
    public void run() {
   
        //Runnable执行代理
        System.out.println("do something");
        runnable.run();
        System.out.println("do something");
    }
    public static void main(String[] args) {
   
        new Thread(new RunnableProxy(()-> System.out.println("hi"))).start();
    }
}

外观

比较简单的一个模式,基本思想是:如果客户端需要和多个子系统交互,那么可以提供一个中介,客户端和中介交互,中介和各子系统交互。
应用案例:网关、nginx

组合

常用于树形数据结构,把叶子结点和父节点统一管理,比如菜单。
代码示例:

public class Menu {
   

    private String name;

    private List<Menu> childMenu;
}

行为型模式

用于对象之间的职责及其提供服务的分配方式。重点关注对象如何协作,描述一组对象如何协作完成一个整体任务。

责任链

一种处理请求的模式,把多个处理器串成链,依次处理,能让多个处理器都有机会处理,或者某个处理器请求成功为止。
应用场景:Filter,Interceptor
代码示例:

public interface Filter {
   
    boolean doFilter();
}
public class Filter1 implements Filter{
   
    @Override
    public boolean doFilter() {
   
        System.out.println("Filter1.....");
        return false;
    }
}
public class Filter2 implements Filter{
   
    @Override
    public boolean doFilter() {
   
        System.out.println("Filter2.....");
        return false;
    }
}
//责任链
public class FilterChain {
   
    private List<Filter> filters=new ArrayList<>();
    //将多个处理器串联起来
    public void add(Filter filter){
   
        filters.add(filter);
    }
    public boolean doFilter(){
   
        //串联执行
        for (Filter filter:filters){
   
            if (!filter.doFilter())return false;
        }
        return true;
    }

    public static void main(String[] args) {
   
        FilterChain chain=new FilterChain();
        chain.add(new Filter1());
        chain.add(new Filter2());
        chain.doFilter();
    }
}

备忘录

捕捉一个对象当时的状态,并在该对象之外保存这个状态,在某个时候可以恢复状态。
应用场景:几乎所有的软件都用到了备忘录模式。比如说保存、回退。
代码示例:


public class Memento implements Serializable{
   
    //备忘对象
    private MementoObj obj = new MementoObj();

    private class MementoObj implements Serializable {
   
        private String state = "old";

        public void setState(String state) {
   
            this.state = state;
        }

        public String getState() {
   
            return state;
        }
    }
    //记录状态
    public void save() throws IOException {
   
        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(new File("obj.data")));
        oos.writeObject(obj);
        oos.close();
    }
    //回滚状态
    public void load() throws IOException, ClassNotFoundException {
   
        ObjectInputStream ois = new ObjectInputStream(new FileInputStream(new File("obj.data")));
        obj= (MementoObj) ois.readObject();
        ois.close();
    }

    public static void main(String[] args) throws IOException, ClassNotFoundException {
   
        Memento memento=new Memento();
        memento.save();
        memento.obj.setState("new");
        System.out.println("新的状态"+memento.obj.getState());
        memento.load();
        System.out.println("回归到旧的状态"+memento.obj.getState());
    }
}

迭代器

提供统一的遍历接口,保证调用者以相同的接口遍历各种数据结构的集合。
应用场景:各个集合对Iterator具体实现,比如ArrayList、HashMap等。

观察者

简单理解:当一个对象状态发生改变时,所有观察它的对象都被通知。
应用场景:发布-订阅
代码示例:

//观察者接口
public interface Observer {
   
    void publish(Event event);
}
//观察事件
enum Event {
   
    cry, hug
}
//具体观察者
class Mom implements Observer {
   
    @Override
    public void publish(Event event) {
   
        System.out.println(event + ",mom coming");
    }
}
//具体观察者
class Dad implements Observer {
   
    @Override
    public void publish(Event event) {
   
        System.out.println(event + ",wait wait");
    }
}
//被观察者
class Child {
   
    List<Observer> observerList = new ArrayList<>();
    //模拟注入观察者
    {
   
        observerList.add(new Mom());
        observerList.add(new Dad());
    }
    //被观察者某个事件发生后通知观察者
    public void action(Event event) {
   
        for (Observer observer : observerList) {
   
            observer.publish(event);
        }
    }
}

class ObserverMain {
   
    public static void main(String[] args) {
   
        Child child=new Child();
        child.action(Event.cry);
    }
}

模版方法

其核心思想是:定义一个操作的的一系列步骤,对于暂时不确定的步骤,交给子类实现就好。

public abstract class TrafficTemplate {
   
    //定义骨架
    final void goHome() {
   
        int money = money();
        int time = time();
        System.out.println("花费" + money + "元," + time + "小时");
    }

    protected abstract int time();

    protected abstract int money();

    public static void main(String[] args) {
   
        TrafficTemplate trafficTemplate = new Bicycle();
        trafficTemplate.goHome();
    }
}
public class Bicycle extends TrafficTemplate{
   
    @Override
    protected int time() {
   
        return 2;
    }

    @Override
    protected int money() {
   
        return 0;
    }
}
public class Car extends TrafficTemplate{
   
    @Override
    protected int time() {
   
        return 1;
    }

    @Override
    protected int money() {
   
        return 5;
    }
}

策略

定义一组算法并封装起来,运行时可以灵活的使用其中一个。其核心思想是讲容易变换的算法抽离出来作为“策略”参数传递。
应用场景:List.sort(Comparator) 其中Comparator可以看作策略。
代码示例:

//策略接口
public interface Strategy {
   
    void toDO(AtomicInteger number);
}
//具体策略实现
public class PlusStrategy implements Strategy{
   
    @Override
    public void toDO(AtomicInteger number) {
   
        number.incrementAndGet();
    }
}
//具体策略实现
public class SubtractStrategy implements Strategy{
   
    @Override
    public void toDO(AtomicInteger number) {
   
        number.decrementAndGet();
    }
}
public class DoSomething {
   
    @Override
    public void toDO(AtomicInteger number,Strategy plusStrategy) {
   
         plusStrategy.toDO(number);
    }
}
    private static AtomicInteger number = new AtomicInteger();
    public static void main(String[] args) {
   
        DoSomething doSomething=new DoSomething();
        //传入策略执行
        doSomething.toDO(number,new SubtractStrategy());
        System.out.println(number.get());
    }
相关文章
|
设计模式 JSON Java
设计模式下篇
设计模式下篇
42 0
|
设计模式 Java 程序员
java实现23种设计模式-引言
java实现23种设计模式-引言
42 0
|
6月前
|
设计模式
设计模式案例(一)
设计模式案例(一)
45 0
|
6月前
|
设计模式
设计模式案例 (三)
设计模式案例 (三)
41 0
|
设计模式 uml
图解设计模式——学习设计模式之前需要了解的信息
为了方便地编写面向对象程序,我们会使用类库,但是设计模式并非类库。与类库相比,设计模式是一个非常普遍的概念。类库是由程序组合而成的组件,而设计模式则用来表现内部组件是如何被组装的,以及每一个组件是如何通过相互关联来构成一个庞大系统的。
166 1
|
设计模式 存储 算法
23个小案例带你吃透23种设计模式(二)
23个小案例带你吃透23种设计模式
157 0
23个小案例带你吃透23种设计模式(二)
|
设计模式 算法 搜索推荐
23个小案例带你吃透23种设计模式(三)
23个小案例带你吃透23种设计模式
163 0
23个小案例带你吃透23种设计模式(三)
|
设计模式 SQL 安全
23个小案例带你吃透23种设计模式(一)
23个小案例带你吃透23种设计模式
228 0
23个小案例带你吃透23种设计模式(一)
|
设计模式 算法 安全
正确的姿势学习设计模式,设计模式必知必会(第二篇) --- 面试, 提升篇
正确的姿势学习设计模式,设计模式必知必会(第二篇) --- 面试, 提升篇
正确的姿势学习设计模式,设计模式必知必会(第二篇) --- 面试, 提升篇
|
设计模式 消息中间件 算法
面试题(二十五)设计模式
1. 设计模式 1.1 说一说设计模式的六大原则 参考答案 单一职责原则 一个类,应当只有一个引起它变化的原因;即一个类应该只有一个职责。 就一个类而言,应该只专注于做一件事和仅有一个引起变化的原因,这就是所谓的单一职责原则。该原则提出了对对象职责的一种理想期望,对象不应该承担太多职责,正如人不应该一心分为二用。唯有专注,才能保证对象的高内聚;唯有单一,才能保证对象的细粒度。对象的高内聚与细粒度有利于对象的重用。一个庞大的对象承担了太多的职责,当客户端需要该对象的某一个职责时,就不得不将所有的职责都包含进来,从而造成冗余代码。 里氏替换原则 在面向对象的语言中,继承是必不可少的、优秀的语言机制
101 0