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

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

前言

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

设计原则

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

开闭原则

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

里氏替换原则

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

单一职责

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

迪米特法则

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

设计模式

目前常见的设计模式分为以下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());
    }
相关文章
|
6月前
|
设计模式 XML Java
第五篇 设计模式的选择和应用 - 智慧选择与合理实践
第五篇 设计模式的选择和应用 - 智慧选择与合理实践
|
设计模式 Java 程序员
java实现23种设计模式-引言
java实现23种设计模式-引言
42 0
|
设计模式 算法 关系型数据库
设计模式 | 开篇简介
模式是在特定环境下人们解决某类重复出现问题的一套成功或有效的解决方案。
104 1
设计模式 | 开篇简介
|
设计模式 uml
图解设计模式——学习设计模式之前需要了解的信息
为了方便地编写面向对象程序,我们会使用类库,但是设计模式并非类库。与类库相比,设计模式是一个非常普遍的概念。类库是由程序组合而成的组件,而设计模式则用来表现内部组件是如何被组装的,以及每一个组件是如何通过相互关联来构成一个庞大系统的。
165 1
|
设计模式 存储 算法
23个小案例带你吃透23种设计模式(二)
23个小案例带你吃透23种设计模式
154 0
23个小案例带你吃透23种设计模式(二)
|
设计模式 SQL 安全
23个小案例带你吃透23种设计模式(一)
23个小案例带你吃透23种设计模式
228 0
23个小案例带你吃透23种设计模式(一)
|
设计模式 算法 搜索推荐
23个小案例带你吃透23种设计模式(三)
23个小案例带你吃透23种设计模式
161 0
23个小案例带你吃透23种设计模式(三)
|
设计模式 算法 安全
正确的姿势学习设计模式,设计模式必知必会(第二篇) --- 面试, 提升篇
正确的姿势学习设计模式,设计模式必知必会(第二篇) --- 面试, 提升篇
正确的姿势学习设计模式,设计模式必知必会(第二篇) --- 面试, 提升篇
|
设计模式 消息中间件 算法
面试题(二十五)设计模式
1. 设计模式 1.1 说一说设计模式的六大原则 参考答案 单一职责原则 一个类,应当只有一个引起它变化的原因;即一个类应该只有一个职责。 就一个类而言,应该只专注于做一件事和仅有一个引起变化的原因,这就是所谓的单一职责原则。该原则提出了对对象职责的一种理想期望,对象不应该承担太多职责,正如人不应该一心分为二用。唯有专注,才能保证对象的高内聚;唯有单一,才能保证对象的细粒度。对象的高内聚与细粒度有利于对象的重用。一个庞大的对象承担了太多的职责,当客户端需要该对象的某一个职责时,就不得不将所有的职责都包含进来,从而造成冗余代码。 里氏替换原则 在面向对象的语言中,继承是必不可少的、优秀的语言机制
99 0
|
设计模式
设计模式原理还不知道吗?这篇让你彻底明白
设计模式原理还不知道吗?这篇让你彻底明白
设计模式原理还不知道吗?这篇让你彻底明白