Java设计模式大揭秘!23种魔法武器助你编写酷炫代码!
本文最后更新于85 天前,其中的信息可能已经过时,如有错误请发送邮件到sherry.rain@qq.com

今天,我要揭晓Java编程世界的奇妙秘密——23种设计模式!这些设计模式就像是程序员们的魔法武器,能让你的代码变得酷炫起来,让你的项目闪耀光芒!

介绍

设计模式是在软件开发中广泛应用的一种解决问题的方式。它们是从实践中总结出来的经验和最佳实践,可以帮助我们更好地组织和设计我们的代码。

设计模式的目标是提供一种通用的解决方案,用于解决特定类型的问题。它们可以帮助我们构建灵活、可扩展和易于维护的软件系统。设计模式是一种思想和方法的集合,它们描述了如何组织和交互对象,以解决特定的设计问题。

在设计模式的应用过程中,有几个重要的原则需要我们遵循:

  1. 单一职责原则(Single Responsibility Principle,SRP):一个类应该只有一个引起变化的原因。每个类应该只负责一项职责,这样可以提高类的内聚性和可维护性。

  2. 开放封闭原则(Open-Closed Principle,OCP):软件实体(类、模块、函数等)应该对扩展开放,对修改关闭。通过使用抽象和接口来实现可扩展性,而不是直接修改现有代码。

  3. 里氏替换原则(Liskov Substitution Principle,LSP):子类应该能够替换父类并且不影响程序的正确性。这意味着子类必须保持与父类一致的行为规范,以确保代码的正确性和稳定性。

  4. 依赖倒置原则(Dependency Inversion Principle,DIP):高层模块不应该依赖于低层模块,二者都应该依赖于抽象。通过依赖注入和面向接口编程,可以减少模块之间的耦合度。

  5. 接口隔离原则(Interface Segregation Principle,ISP):客户端不应该依赖于它不需要的接口。将大接口拆分为更小的粒度,以确保客户端只需要依赖于它们所需的部分。

  6. 迪米特法则(Law of Demeter,LoD):一个对象应该对其他对象有尽可能少的了解。一个类应该只与它的直接朋友进行交互,不要对外暴露过多的信息。

在接下来的正文中,我们将介绍并详细解释常见的设计模式,并提供示例代码来帮助理解和应用这些模式。让我们一起探索设计模式的奇妙世界,提升我们的编程能力和代码质量。

1.单例模式

解释说明:单例模式就像是程序员的专属宠物,只能有一个实例存在。它保证了在整个应用程序中,只有一个对象被创建和使用。这样,你就能够节约资源,还能让你的程序更加高效。

示例代码演示:

public class Singleton {
    private static Singleton instance;

    private Singleton() {}

    public static synchronized Singleton getInstance() {
        if (instance == null) {
            instance = new Singleton();
        }
        return instance;
    }
}

public class Main {
    public static void main(String[] args) {
        Singleton singleton1 = Singleton.getInstance();
        Singleton singleton2 = Singleton.getInstance();

        System.out.println(singleton1 == singleton2);  // 输出:true
    }
}

应用场景:当你需要在整个程序中共享某个对象时,可以使用单例模式。比如,数据库连接池、线程池等都可以使用单例模式来保证全局唯一性。另外,Spring框架中的bean也是单例模式,这样可以确保在整个应用程序中,只有一个实例被创建,提高了性能和资源利用率。

2.工厂模式

解释说明:工厂模式就像是程序员的定制工作台,能够根据你的需求创建不同的对象。它将对象的创建与使用分离,让你的代码更加灵活,可扩展性更强。

示例代码演示:

public interface Shape {
    void draw();
}

public class Circle implements Shape {
    @Override
    public void draw() {
        System.out.println("画一个圆形");
    }
}

public class Rectangle implements Shape {
    @Override
    public void draw() {
        System.out.println("画一个矩形");
    }
}

public class ShapeFactory {
    public Shape getShape(String shapeType) {
        if (shapeType == null) {
            return null;
        }
        if (shapeType.equalsIgnoreCase("CIRCLE")) {
            return new Circle();
        } else if (shapeType.equalsIgnoreCase("RECTANGLE")) {
            return new Rectangle();
        }
        return null;
    }
}

public class Main {
    public static void main(String[] args) {
        ShapeFactory shapeFactory = new ShapeFactory();

        Shape circle = shapeFactory.getShape("CIRCLE");
        circle.draw();  // 输出:画一个圆形

        Shape rectangle = shapeFactory.getShape("RECTANGLE");
        rectangle.draw();  // 输出:画一个矩形
    }
}

应用场景:当你需要根据不同的条件创建不同的对象时,可以使用工厂模式。比如,根据用户输入的不同形状,创建对应的图形对象。另外,在Spring框架中,通过工厂模式创建bean对象,可以灵活管理和配置各种组件。

3.原型模式

解释说明:原型模式就像是程序员的复制粘贴神器,能够通过复制现有对象来创建新的对象。它避免了对象的重复创建过程,提高了性能和效率。

示例代码演示:

public abstract class Shape implements Cloneable {
    private String id;
    protected String type;

    public abstract void draw();

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    public String getType() {
        return type;
    }

    @Override
    public Object clone() {
        Object clone = null;
        try {
            clone = super.clone();
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
        }
        return clone;
    }
}

public class Rectangle extends Shape {
    public Rectangle() {
        type = "Rectangle";
    }

    @Override
    public void draw() {
        System.out.println("画一个矩形");
    }
}

public class Circle extends Shape {
    public Circle() {
        type = "Circle";
    }

    @Override
    public void draw() {
        System.out.println("画一个圆形");
    }
}

public class ShapeCache {
    private static Map<String, Shape> shapeMap = new HashMap<>();

    public static Shape getShape(String shapeId) {
        Shape cachedShape = shapeMap.get(shapeId);
        return (Shape) cachedShape.clone();
    }

    public static void loadCache() {
        Circle circle = new Circle();
        circle.setId("1");
        shapeMap.put(circle.getId(), circle);

        Rectangle rectangle = new Rectangle();
        rectangle.setId("2");
        shapeMap.put(rectangle.getId(), rectangle);
    }
}

public class Main {
    public static void main(String[] args) {
        ShapeCache.loadCache();

        Shape clonedShape1 = ShapeCache.getShape("1");
        System.out.println("Shape : " + clonedShape1.getType());  // 输出:Shape : Circle

        Shape clonedShape2 = ShapeCache.getShape("2");
        System.out.println("Shape : " + clonedShape2.getType());  // 输出:Shape : Rectangle
    }
}

应用场景:当你需要根据现有对象创建新的对象时,可以使用原型模式。比如,在图形编辑器中,通过复制一个图形对象来创建新的图形对象,而不需要重新绘制。

4.建造者模式

解释说明:建造者模式就像是程序员的定制工程师,能够一步一步构建复杂对象。它将对象的构建过程与表示分离,使得同样的构建过程可以创建不同的表示。

示例代码演示:

public class Meal {
    private List<Item> items = new ArrayList<>();

    public void addItem(Item item) {
        items.add(item);
    }

    public float getCost() {
        float cost = 0.0f;
        for (Item item : items) {
            cost += item.price();
        }
        return cost;
    }

    public void showItems() {
        for (Item item : items) {
            System.out.print("Item : " + item.name());
            System.out.print(", Packing : " + item.packing().pack());
            System.out.println(", Price : " + item.price());
        }
    }
}

public interface Item {
    String name();
    Packing packing();
    float price();
}

public interface Packing {
    String pack();
}

public abstract class Burger implements Item {
    @Override
    public Packing packing() {
        return new Wrapper();
    }

    @Override
    public abstract float price();
}

public abstract class ColdDrink implements Item {
    @Override
    public Packing packing() {
        return new Bottle();
    }

    @Override
    public abstract float price();
}

public class VegBurger extends Burger {
    @Override
    public String name() {
        return "Veg Burger";
    }

    @Override
    public float price() {
        return 25.0f;
    }
}

public class ChickenBurger extends Burger {
    @Override
    public String name() {
        return "Chicken Burger";
    }

    @Override
    public float price() {
        return 50.5f;
    }
}

public class Coke extends ColdDrink {
    @Override
    public String name() {
        return "Coke";
    }

    @Override
    public float price() {
        return 30.0f;
    }
}

public class Pepsi extends ColdDrink {
    @Override
    public String name() {
        return "Pepsi";
    }

    @Override
    public float price() {
        return 35.0f;
    }
}

public class Wrapper implements Packing {
    @Override
    public String pack() {
        return "Wrapper";
    }
}

public class Bottle implements Packing {
    @Override
    public String pack() {
        return "Bottle";
    }
}

public class MealBuilder {
    public Meal prepareVegMeal() {
        Meal meal = new Meal();
        meal.addItem(new VegBurger());
        meal.addItem(new Coke());
        return meal;
    }

    public Meal prepareNonVegMeal() {
        Meal meal = new Meal();
        meal.addItem(new ChickenBurger());
        meal.addItem(new Pepsi());
        return meal;
    }
}

public class Main {
    public static void main(String[] args) {
        MealBuilder mealBuilder = new MealBuilder();

        Meal vegMeal = mealBuilder.prepareVegMeal();
        System.out.println("Veg Meal");
        vegMeal.showItems();
        System.out.println("Total Cost: " + vegMeal.getCost());  // 输出:Total Cost: 55.0

        Meal nonVegMeal = mealBuilder.prepareNonVegMeal();
        System.out.println("\nNon-Veg Meal");
        nonVegMeal.showItems();
        System.out.println("Total Cost: " + nonVegMeal.getCost());  // 输出:Total Cost: 85.5
    }
}

应用场景:当你需要一步一步构建复杂对象时,可以使用建造者模式。比如,在快餐店中,通过不同的组合来构建套餐,可以根据顾客的需求定制不同的套餐。

5.适配器模式

解释说明:适配器模式就像是程序员的翻译官,能够将不兼容的接口转换成可兼容的接口。它使得原本由于接口不兼容而无法一起工作的类能够协同工作。

示例代码演示:

public interface MediaPlayer {
    void play(String audioType, String fileName);
}

public interface AdvancedMediaPlayer {
    void playVlc(String fileName);
    void playMp4(String fileName);
}

public class VlcPlayer implements AdvancedMediaPlayer {
    @Override
    public void playVlc(String fileName) {
        System.out.println("Playing vlc file. Name: " + fileName);
    }

    @Override
    public void playMp4(String fileName) {
        // 什么也不做
    }
}

public class Mp4Player implements AdvancedMediaPlayer {
    @Override
    public void playVlc(String fileName) {
        // 什么也不做
    }

    @Override
    public void playMp4(String fileName) {
        System.out.println("Playing mp4 file. Name: " + fileName);
    }
}

public class MediaAdapter implements MediaPlayer {
    private AdvancedMediaPlayer advancedMusicPlayer;

    public MediaAdapter(String audioType) {
        if (audioType.equalsIgnoreCase("vlc")) {
            advancedMusicPlayer = new VlcPlayer();
        } else if (audioType.equalsIgnoreCase("mp4")) {
            advancedMusicPlayer = new Mp4Player();
        }
    }

    @Override
    public void play(String audioType, String fileName) {
        if (audioType.equalsIgnoreCase("vlc")) {
            advancedMusicPlayer.playVlc(fileName);
        } else if (audioType.equalsIgnoreCase("mp4")) {
            advancedMusicPlayer.playMp4(fileName);
        }
    }
}

public class AudioPlayer implements MediaPlayer {
    MediaAdapter mediaAdapter;

    @Override
    public void play(String audioType, String fileName) {
        if (audioType.equalsIgnoreCase("mp3")) {
            System.out.println("Playing mp3 file. Name: " + fileName);
        } else if (audioType.equalsIgnoreCase("vlc") || audioType.equalsIgnoreCase("mp4")) {
            mediaAdapter = new MediaAdapter(audioType);
            mediaAdapter.play(audioType, fileName);
        } else {
            System.out.println("Invalid media. " + audioType + " format not supported");
        }
    }
}

public class Main {
    public static void main(String[] args) {
        AudioPlayer audioPlayer = new AudioPlayer();

        audioPlayer.play("mp3", "beyond_the_horizon.mp3");
        audioPlayer.play("mp4", "alone.mp4");
        audioPlayer.play("vlc", "far_far_away.vlc");
        audioPlayer.play("avi", "mind_me.avi");  // 输出:Invalid media. avi format not supported
    }
}

应用场景:当你需要将一个类的接口转换成另一个类的接口时,可以使用适配器模式。比如,播放器只支持播放mp3文件,但是你有一些vlc和mp4格式的文件,通过适配器模式,可以让播放器也能够播放这些格式的文件。

6.桥接模式

解释说明:桥接模式就像是程序员的桥梁工程师,能够将抽象和实现解耦,让它们可以独立地变化。它提供了一种将抽象部分与实现部分分离的方法,使得二者可以独立地变化,而不会相互影响。

示例代码演示:

public interface DrawAPI {
    void drawCircle(int radius, int x, int y);
}

public class RedCircle implements DrawAPI {
    @Override
    public void drawCircle(int radius, int x, int y) {
        System.out.println("Drawing Circle[ color: red, radius: " + radius + ", x: " + x + ", " + y + "]");
    }
}

public class GreenCircle implements DrawAPI {
    @Override
    public void drawCircle(int radius, int x, int y) {
        System.out.println("Drawing Circle[ color: green, radius: " + radius + ", x: " + x + ", " + y + "]");
    }
}

public abstract class Shape {
    protected DrawAPI drawAPI;

    protected Shape(DrawAPI drawAPI) {
        this.drawAPI = drawAPI;
    }

    public abstract void draw();
}

public class Circle extends Shape {
    private int x, y, radius;

    public Circle(int x, int y, int radius, DrawAPI drawAPI) {
        super(drawAPI);
        this.x = x;
        this.y = y;
        this.radius = radius;
    }

    @Override
    public void draw() {
        drawAPI.drawCircle(radius, x, y);
    }
}

public class Main {
    public static void main(String[] args) {
        Shape redCircle = new Circle(100, 100, 10, new RedCircle());
        Shape greenCircle = new Circle(100,100, 10, new GreenCircle());

    redCircle.draw();    // 输出:Drawing Circle[ color: red, radius: 10, x: 100, 100]
    greenCircle.draw();  // 输出:Drawing Circle[ color: green, radius: 10, x: 100, 100]
}

应用场景:当你需要将抽象部分和实现部分分离开来,并且它们可以独立地变化时,可以使用桥接模式。比如,在图形绘制中,可以将不同颜色的圆形绘制实现和具体的圆形对象分离开来,使得它们可以独立地进行变化和扩展。

7.组合模式

解释说明:组合模式就像是程序员的组织架构,能够将对象组合成树形结构来表示部分-整体的层次关系。它使得客户端对单个对象和组合对象的使用具有一致性。

示例代码演示:

public interface Employee {
    void add(Employee employee);
    void remove(Employee employee);
    void display(int depth);
}

public class Developer implements Employee {
    private String name;

    public Developer(String name) {
        this.name = name;
    }

    @Override
    public void add(Employee employee) {
        // 什么也不做,因为开发人员没有下属
    }

    @Override
    public void remove(Employee employee) {
        // 什么也不做,因为开发人员没有下属
    }

    @Override
    public void display(int depth) {
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < depth; i++) {
            sb.append("-");
        }
        System.out.println(sb.toString() + " " + name);
    }
}

public class Manager implements Employee {
    private String name;
    private List<Employee> subordinates = new ArrayList<>();

    public Manager(String name) {
        this.name = name;
    }

    @Override
    public void add(Employee employee) {
        subordinates.add(employee);
    }

    @Override
    public void remove(Employee employee) {
        subordinates.remove(employee);
    }

    @Override
    public void display(int depth) {
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < depth; i++) {
            sb.append("-");
        }
        System.out.println(sb.toString() + " " + name);

        for (Employee subordinate : subordinates) {
            subordinate.display(depth + 2);
        }
    }
}

public class Main {
    public static void main(String[] args) {
        Employee ceo = new Manager("John");

        Employee headOfDevelopment = new Manager("Mike");
        Employee developer1 = new Developer("Tom");
        Employee developer2 = new Developer("Jerry");

        headOfDevelopment.add(developer1);
        headOfDevelopment.add(developer2);

        Employee headOfSales = new Manager("Mary");
        Employee salesExecutive1 = new Developer("Bob");
        Employee salesExecutive2 = new Developer("Alice");

        headOfSales.add(salesExecutive1);
        headOfSales.add(salesExecutive2);

        ceo.add(headOfDevelopment);
        ceo.add(headOfSales);

        ceo.display(1);
    }
}

应用场景:当你需要将对象组织成树形结构来表示部分-整体的层次关系时,可以使用组合模式。比如,在公司组织架构中,可以使用组合模式来表示CEO、经理和员工之间的关系。

8.装饰器模式

解释说明:装饰器模式就像是程序员的时尚造型师,能够动态地给对象增加额外的功能。它通过创建一个包装对象来包裹原始对象,从而在不改变原始对象的情况下,动态地扩展其功能。

示例代码演示:

public interface Shape {
    void draw();
}

public class Circle implements Shape {
    @Override
    public void draw() {
        System.out.println("Shape: Circle");
    }
}

public abstract class ShapeDecorator implements Shape {
    protected Shape decoratedShape;

    public ShapeDecorator(Shape decoratedShape) {
        this.decoratedShape = decoratedShape;
    }

    @Override
    public void draw() {
        decoratedShape.draw();
    }
}

public class RedShapeDecorator extends ShapeDecorator {
    public RedShapeDecorator(Shape decoratedShape) {
        super(decoratedShape);
    }

    @Override
    public void draw() {
        decoratedShape.draw();
        setRedBorder(decoratedShape);
    }

    private void setRedBorder(Shape decoratedShape) {
        System.out.println("Border Color: Red");
    }
}

public class Main {
    public static void main(String[] args) {
        Shape circle = new Circle();

        Shape redCircle = new RedShapeDecorator(new Circle());
        Shape redRectangle = new RedShapeDecorator(new Rectangle());

        System.out.println("Circle with normal border");
        circle.draw();  // 输出:Shape: Circle

        System.out.println("\nCircle with red border");
        redCircle.draw();

        System.out.println("\nRectangle with red border");
        redRectangle.draw();
    }
}

应用场景:当你需要在不改变原始对象的情况下,动态地给对象增加额外的功能时,可以使用装饰器模式。比如,在图形绘制中,可以使用装饰器模式来动态地给图形对象增加边框颜色。

9.外观模式

解释说明:外观模式就像是程序员的便利店,提供了一个统一的接口,隐藏了系统的复杂性,使得客户端更加简单和方便地使用系统。

示例代码演示:

public interface Shape {
    void draw();
}

public class Circle implements Shape {
    @Override
    public void draw() {
        System.out.println("Circle::draw()");
    }
}

public class Rectangle implements Shape {
    @Override
    public void draw() {
        System.out.println("Rectangle::draw()");
    }
}

public class Square implements Shape {
    @Override
    public void draw() {
        System.out.println("Square::draw()");
    }
}

public class ShapeMaker {
    private Shape circle;
    private Shape rectangle;
    private Shape square;

    public ShapeMaker() {
        circle = new Circle();
        rectangle = new Rectangle();
        square = new Square();
    }

    public void drawCircle() {
        circle.draw();
    }

    public void drawRectangle() {
        rectangle.draw();
    }

    public void drawSquare() {
        square.draw();
    }
}

public class Main {
    public static void main(String[] args) {
        ShapeMaker shapeMaker = new ShapeMaker();

        shapeMaker.drawCircle();     // 输出:Circle::draw()
        shapeMaker.drawRectangle();  // 输出:Rectangle::draw()
        shapeMaker.drawSquare();     // 输出:Square::draw()
    }
}

应用场景:当你需要为客户端提供一个简单和方便的接口,隐藏系统的复杂性时,可以使用外观模式。比如,在图形绘制中,可以使用外观模式将不同形状的绘制过程封装起来,提供一个统一的绘制接口。

10.享元模式

解释说明:享元模式就像是程序员的共享缓存,通过共享对象来减少内存的使用。它通过将对象的状态分为内部状态和外部状态,将共享对象的内部状态存储在享元对象内部,而外部状态由客户端传入。

示例代码演示:

public interface Shape {
    void draw();
}

public class Circle implements Shape {
    private String color;
    private int x;
    private int y;
    private int radius;

    public Circle(String color) {
        this.color = color;
    }

    public void setX(int x) {
        this.x = x;
    }

    public void setY(int y) {
        this.y = y;
    }

    public void setRadius(int radius) {
        this.radius = radius;
    }

    @Override
    public void draw() {
        System.out.println("Circle: Draw() [Color : " + color + ", x : " + x + ", y :" + y + ", radius :" + radius);
    }
}

public class ShapeFactory {
    private static final Map<String, Shape> circleMap = new HashMap<>();

    public static Shape getCircle(String color) {
        Circle circle = (Circle) circleMap.get(color);

        if (circle == null) {
            circle = new Circle(color);
            circleMap.put(color, circle);
            System.out.println("Creating circle of color : " + color);
        }

        return circle;
    }
}

public class Main {
    private static final String[] colors = {"Red", "Green", "Blue", "White", "Black"};

    public static void main(String[] args) {
        for (int i = 0; i < 20; i++) {
            Circle circle = (Circle) ShapeFactory.getCircle(getRandomColor());
            circle.setX(getRandomX());
            circle.setY(getRandomY());
            circle.setRadius(100);
            circle.draw();
        }
    }

    private static String getRandomColor() {
        return colors[(int) (Math.random() * colors.length)];
    }

    private static int getRandomX() {
        return (int) (Math.random() * 100);
    }

    private static int getRandomY() {
        return (int) (Math.random() * 100);
    }
}

应用场景:当你需要创建大量相似对象,并且这些对象可以共享一部分状态时,可以使用享元模式。比如,在图形绘制中,可以使用享元模式来共享相同颜色的圆形对象,减少内存的使用。

11.代理模式

解释说明:代理模式就像是程序员的替身,能够控制对对象的访问。它通过创建一个代理对象来控制对真实对象的访问,可以在访问对象之前或之后添加一些额外的操作。

示例代码演示:

public interface Image {
    void display();
}

public class RealImage implements Image {
    private String filename;

    public RealImage(String filename) {
        this.filename = filename;
        loadFromDisk();
    }

    private void loadFromDisk() {
        System.out.println("Loading image: " + filename);
    }

    @Override
    public void display() {
        System.out.println("Displaying image: " + filename);
    }
}

public class ProxyImage implements Image {
    private String filename;
    private RealImage realImage;

    public ProxyImage(String filename) {
        this.filename = filename;
    }

    @Override
    public void display() {
        if (realImage == null) {
            realImage = new RealImage(filename);
        }
        realImage.display();
    }
}

public class Main {
    public static void main(String[] args) {
        Image image1 = new ProxyImage("image1.jpg");
        image1.display();  // 输出:Loading image: image1.jpg \n Displaying image: image1.jpg

        Image image2 = new ProxyImage("image2.jpg");
        image2.display();  // 输出:Loading image: image2.jpg \n Displaying image: image2.jpg
    }
}

应用场景:当你需要控制对对象的访问,或者在访问对象之前或之后添加一些额外的操作时,可以使用代理模式。比如,在加载大型图片时,可以使用代理模式来延迟加载图片,减少内存的占用。

12.责任链模式

解释说明:责任链模式就像是程序员的工作流程,能够将请求从一个处理者传递到下一个处理者,直到请求被处理完成。它将请求的发送者和接收者解耦,使得多个对象都有机会处理请求。

示例代码演示:

public abstract class Logger {
    public static int INFO = 1;
    public static int DEBUG = 2;
    public static int ERROR = 3;

    protected int level;
    protected Logger nextLogger;

    public void setNextLogger(Logger nextLogger) {
        this.nextLogger = nextLogger;
    }

    public void logMessage(int level, String message) {
        if (this.level <= level) {
            write(message);
        }
        if (nextLogger != null) {
            nextLogger.logMessage(level, message);
        }
    }

    abstract protected void write(String message);
}

public class ConsoleLogger extends Logger {
    public ConsoleLogger(int level) {
        this.level = level;
    }

    @Override
    protected void write(String message) {
        System.out.println("Console Logger: " + message);
    }
}

public class FileLogger extends Logger {
    public FileLogger(int level) {
        this.level = level;
    }

    @Override
    protected void write(String message) {
        System.out.println("File Logger: " + message);
    }
}

public class ErrorLogger extends Logger {
    public ErrorLogger(int level) {
        this.level = level;
    }

    @Override
    protected void write(String message) {
        System.out.println("Error Logger: " + message);
    }
}

public class Main {
    private static Logger getChainOfLoggers() {
        Logger errorLogger = new ErrorLogger(Logger.ERROR);
        Logger fileLogger = new FileLogger(Logger.DEBUG);
        Logger consoleLogger = new ConsoleLogger(Logger.INFO);

        errorLogger.setNextLogger(fileLogger);
        fileLogger.setNextLogger(consoleLogger);

        return errorLogger;
    }

    public static void main(String[] args) {
        Logger loggerChain = getChainOfLoggers();

        loggerChain.logMessage(Logger.INFO, "This is an information.");
        loggerChain.logMessage(Logger.DEBUG, "This is a debug level information.");
        loggerChain.logMessage(Logger.ERROR, "This is an error information.");
    }
}

应用场景:当你有多个对象可以处理请求,并且你希望请求沿着对象链传递直到被处理完成时,可以使用责任链模式。比如,在日志记录中,可以使用责任链模式来根据日志的级别选择不同的处理者进行处理。

13.命令模式

解释说明:命令模式就像是程序员的遥控器,能够将请求封装成对象,从而可以将请求的发送者和接收者解耦。它允许请求的参数化,支持请求的排队和记录操作日志。

示例代码演示:

public interface Command {
    void execute();
}

public class Light {
    public void turnOn() {
        System.out.println("Light is on");
    }

    public void turnOff() {
        System.out.println("Light is off");
    }
}

public class LightOnCommand implements Command {
    private Light light;

    public LightOnCommand(Light light) {
        this.light = light;
    }

    @Override
    public void execute() {
        light.turnOn();
    }
}

public class LightOffCommand implements Command {
    private Light light;

    public LightOffCommand(Light light) {
        this.light = light;
    }

    @Override
    public void execute() {
        light.turnOff();
    }
}

public class RemoteControl {
    private Command command;

    public void setCommand(Command command) {
        this.command = command;
    }

    public void pressButton() {
        command.execute();
    }
}

public class Main {
    public static void main(String[] args) {
        Light livingRoomLight = new Light();

        Command livingRoomLightOnCommand = new LightOnCommand(livingRoomLight);
        Command livingRoomLightOffCommand = new LightOffCommand(livingRoomLight);

        RemoteControl remoteControl = new RemoteControl();

        remoteControl.setCommand(livingRoomLightOnCommand);
        remoteControl.pressButton();  // 输出:Light is on

        remoteControl.setCommand(livingRoomLightOffCommand);
        remoteControl.pressButton();  // 输出:Light is off
    }
}

应用场景:当你需要将请求封装成对象,并且可以对请求进行参数化、排队和记录操作日志时,可以使用命令模式。比如,在遥控器中,可以使用命令模式将不同的操作封装成命令对象,从而可以方便地控制不同的设备。

14.迭代器模式

解释说明:迭代器模式就像是程序员的迭代器,能够顺序访问一个聚合对象中的各个元素,而又不暴露聚合对象的内部表示。它将遍历的责任从聚合对象中分离出来,使得聚合对象和遍历算法可以独立地变化。

示例代码演示:

public interface Iterator {
    boolean hasNext();
    Object next();
}

public interface Container {
    Iterator getIterator();
}

public class NameRepository implements Container {
    private String[] names = {"Alice", "Bob", "Charlie", "David"};

    @Override
    public Iterator getIterator() {
        return new NameIterator();
    }

    private class NameIterator implements Iterator {
        private int index;

        @Override
        public boolean hasNext() {
            return index < names.length;
        }

        @Override
        public Object next() {
            if (this.hasNext()) {
                return names[index++];
            }
            return null;
        }
    }
}

public class Main {
    public static void main(String[] args) {
        NameRepository nameRepository = new NameRepository();

        for (Iterator iterator = nameRepository.getIterator(); iterator.hasNext();) {
            String name = (String) iterator.next();
            System.out.println("Name: " + name);
        }
    }
}

应用场景:当你需要顺序访问一个聚合对象中的各个元素,并且又不暴露聚合对象的内部表示时,可以使用迭代器模式。比如,在一个名字列表中,可以使用迭代器模式来依次访问每个名字。

15.中介者模式

解释说明:中介者模式就像是程序员的调停者,能够封装一系列对象之间的交互,使得对象之间不直接相互通信,而是通过中介者进行通信。它减少了对象之间的耦合度,使得系统更加灵活。

示例代码演示:

public interface ChatMediator {
    void sendMessage(String message, User user);
}

public class ChatMediatorImpl implements ChatMediator {
    private List<User> users;

    public ChatMediatorImpl() {
        this.users = new ArrayList<>();
    }

    @Override
    public void sendMessage(String message, User user) {
        for (User u : users) {
            if (u != user) {
                u.receiveMessage(message);
            }
        }
    }

    public void addUser(User user) {
        users.add(user);
    }
}

public abstract class User {
    protected ChatMediator mediator;
    protected String name;

    public User(ChatMediator mediator, String name) {
        this.mediator = mediator;
        this.name = name;
    }

    public abstract void sendMessage(String message);
    public abstract void receiveMessage(String message);
}

public class ChatUser extends User {
    public ChatUser(ChatMediator mediator, String name) {
        super(mediator, name);
    }

    @Override
    public void sendMessage(String message) {
        System.out.println(name + " sends message: " + message);
        mediator.sendMessage(message, this);
    }

    @Override
    public void receiveMessage(String message) {
        System.out.println(name + " receives message: " + message);
    }
}

public class Main {
    public static void main(String[] args) {
        ChatMediator mediator = new ChatMediatorImpl();

        User user1 = new ChatUser(mediator, "User1");
        User user2 = new ChatUser(mediator, "User2");
        User user3 = new ChatUser(mediator, "User3");

        mediator.addUser(user1);
        mediator.addUser(user2);
        mediator.addUser(user3);

        user1.sendMessage("Hello, everyone!");  
        // 输出:User1 sends message: Hello, everyone!
        //      User2 receives message: Hello, everyone!
        //      User3 receives message: Hello, everyone!
    }
}

应用场景:当你需要封装一系列对象之间的交互,使得对象之间不直接相互通信,而是通过中介者进行通信时,可以使用中介者模式。比如,在一个聊天室中,可以使用中介者模式来将用户之间的聊天信息传递给其他用户。

16.备忘录模式

解释说明:备忘录模式就像是程序员的时间机器,能够在不破坏封装性的前提下,捕获一个对象的内部状态,并在之后恢复到这个状态。它提供了一种保存和恢复对象状态的方法。

示例代码演示:

public class Memento {
    private String state;

    public Memento(String state) {
        this.state = state;
    }

    public String getState() {
        return state;
    }
}

public class Originator {
    private String state;

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

    public String getState() {
        return state;
    }

    public Memento saveStateToMemento() {
        return new Memento(state);
    }

    public void restoreStateFromMemento(Memento memento) {
        state = memento.getState();
    }
}

public class Caretaker {
    private List<Memento> mementoList = new ArrayList<>();

    public void addMemento(Memento memento) {
        mementoList.add(memento);
    }

    public Memento getMemento(int index) {
        return mementoList.get(index);
    }
}

public class Main {
    public static void main(String[] args) {
        Originator originator = new Originator();
        Caretaker caretaker = new Caretaker();

        originator.setState("State 1");
        originator.setState("State 2");
        caretaker.addMemento(originator.saveStateToMemento());

        originator.setState("State 3");
        caretaker.addMemento(originator.saveStateToMemento());

        originator.setState("State 4");

        System.out.println("Current State: " + originator.getState());  // 输出:Current State: State 4

        originator.restoreStateFromMemento(caretaker.getMemento(1));

        System.out.println("Restored State: " + originator.getState());  // 输出:Restored State: State 3
    }
}

应用场景:当你需要保存和恢复对象的内部状态时,可以使用备忘录模式。比如,在游戏中,可以使用备忘录模式来保存游戏的进度,并在之后恢复到保存的进度。

17.解释器模式

解释说明:解释器模式就像是程序员的语言解析器,能够解释和执行特定的语言语法。它定义了一个语言的文法,并且通过解释器来解释和执行该语法。

示例代码演示:

public interface Expression {
    boolean interpret(String context);
}

public class TerminalExpression implements Expression {
    private String data;

    public TerminalExpression(String data) {
        this.data = data;
    }

    @Override
    public boolean interpret(String context) {
        if (context.contains(data)) {
            return true;
        }
        return false;
    }
}

public class OrExpression implements Expression {
    private Expression expr1;
    private Expression expr2;

    public OrExpression(Expression expr1, Expression expr2) {
        this.expr1 = expr1;
        this.expr2 = expr2;
    }

    @Override
    public boolean interpret(String context) {
        return expr1.interpret(context) || expr2.interpret(context);
    }
}

public class AndExpression implements Expression {
    private Expression expr1;
    private Expression expr2;

    public AndExpression(Expression expr1, Expression expr2) {
        this.expr1 = expr1;
        this.expr2 = expr2;
    }

    @Override
    public boolean interpret(String context) {
        return expr1.interpret(context) && expr2.interpret(context);
    }
}

public class Main {
    public static void main(String[] args) {
        Expression robert = new TerminalExpression("Robert");
        Expression john = new TerminalExpression("John");

        Expression orExpression = new OrExpression(robert, john);
        Expression andExpression = new AndExpression(robert, john);

        System.out.println("Robert is male? " + orExpression.interpret("Robert"));  // 输出:Robert is male? true
        System.out.println("Robert and John are both male? " + andExpression.interpret("Robert John"));  // 输出:Robert and John are both male? true
    }
}

应用场景:当你需要解释和执行特定的语言语法时,可以使用解释器模式。比如,在编译器中,可以使用解释器模式来解析和执行编程语言的语法。

18.观察者模式

解释说明:观察者模式就像是程序员的订阅号,能够定义一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都会得到通知和更新。

示例代码演示:

import java.util.ArrayList;
import java.util.List;

public class Subject {
    private List<Observer> observers = new ArrayList<>();
    private int state;

    public int getState() {
        return state;
    }

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

    public void attach(Observer observer) {
        observers.add(observer);
    }

    public void notifyAllObservers() {
        for (Observer observer : observers) {
            observer.update();
        }
    }
}

public abstract class Observer {
    protected Subject subject;

    public abstract void update();
}

public class BinaryObserver extends Observer {
    public BinaryObserver(Subject subject) {
        this.subject = subject;
        this.subject.attach(this);
    }

    @Override
    public void update() {
        System.out.println("Binary String: " + Integer.toBinaryString(subject.getState()));
    }
}

public class OctalObserver extends Observer {
    public OctalObserver(Subject subject) {
        this.subject = subject;
        this.subject.attach(this);
    }

    @Override
    public void update() {
        System.out.println("Octal String: " + Integer.toOctalString(subject.getState()));
    }
}

public class HexaObserver extends Observer {
    public HexaObserver(Subject subject) {
        this.subject = subject;
        this.subject.attach(this);
    }

    @Override
    public void update() {
        System.out.println("Hexadecimal String: " + Integer.toHexString(subject.getState()));
    }
}

public class Main {
    public static void main(String[] args) {
        Subject subject = new Subject();

        new BinaryObserver(subject);
        new OctalObserver(subject);
        new HexaObserver(subject);

        System.out.println("First state change: 15");
        subject.setState(15);
        // 输出:
        // Binary String: 1111
        // Octal String: 17
        // Hexadecimal String: f

        System.out.println("\nSecond state change: 10");
        subject.setState(10);
        // 输出:
        // Binary String: 1010
        // Octal String: 12
        // Hexadecimal String: a
    }
}

应用场景:当一个对象的状态发生改变时,需要通知和更新其他对象时,可以使用观察者模式。比如,在一个新闻订阅系统中,可以使用观察者模式来订阅和接收不同类型的新闻。

19.状态模式

解释说明:状态模式就像是程序员的状态机,能够在对象内部状态改变时改变其行为。它将对象的行为和状态分离开来,使得状态的改变不影响行为的变化。

示例代码演示:

public interface State {
    void doAction(Context context);
}

public class StartState implements State {
    @Override
    public void doAction(Context context) {
        System.out.println("Player is in start state");
        context.setState(this);
    }

    @Override
    public String toString() {
        return "Start State";
    }
}

public class StopState implements State {
    @Override
    public void doAction(Context context) {
        System.out.println("Player is in stop state");
        context.setState(this);
    }

    @Override
    public String toString() {
        return "Stop State";
    }
}

public class Context {
    private State state;

    public Context() {
        state = null;
    }

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

    public State getState() {
        return state;
    }
}

public class Main {
    public static void main(String[] args) {
        Context context = new Context();

        StartState startState = new StartState();
        startState.doAction(context);
        System.out.println(context.getState().toString());  // 输出:Start State

        StopState stopState = new StopState();
        stopState.doAction(context);
        System.out.println(context.getState().toString());  // 输出:Stop State
    }
}

应用场景:当对象的行为取决于其内部状态,并且需要在状态改变时改变其行为时,可以使用状态模式。比如,在音乐播放器中,可以使用状态模式来控制播放器的状态,如播放、暂停和停止。

20.策略模式

解释说明:策略模式就像是程序员的智囊团,能够定义一系列算法,并将其封装起来,使得可以互相替换。它使得算法可以独立于客户端而变化。

示例代码演示:

public interface Strategy {
    int doOperation(int num1, int num2);
}

public class OperationAdd implements Strategy {
    @Override
    public int doOperation(int num1, int num2) {
        return num1 + num2;
    }
}

public class OperationSubtract implements Strategy {
    @Override
    public int doOperation(int num1, int num2) {
        return num1 - num2;
    }
}

public class OperationMultiply implements Strategy {
    @Override
    public int doOperation(int num1, int num2) {
        return num1 * num2;
    }
}

public class Context {
    private Strategy strategy;

    public Context(Strategy strategy) {
        this.strategy = strategy;
    }

    public int executeStrategy(int num1, int num2) {
        return strategy.doOperation(num1, num2);
    }
}

public class Main {
    public static void main(String[] args) {
        Context context = new Context(new OperationAdd());
        System.out.println("10 + 5 = " + context.executeStrategy(10, 5));  // 输出:10 + 5 = 15

        context = new Context(new OperationSubtract());
        System.out.println("10 - 5 = " + context.executeStrategy(10, 5));  // 输出:10 - 5 = 5

        context = new Context(new OperationMultiply());
        System.out.println("10 * 5 = " + context.executeStrategy(10, 5));  // 输出:10 * 5 = 50
    }
}

应用场景:当有多个算法可以互相替换,并且客户端不需要知道具体的算法实现时,可以使用策略模式。比如,在支付系统中,可以使用策略模式来实现不同的支付方式,如支付宝、微信支付和银行卡支付。

21.访问者模式

解释说明:访问者模式就像是程序员的旅行者,能够在不改变被访问的类的前提下,定义一个新的操作。它将数据结构与操作分离开来,使得可以添加新的操作而不影响现有的类。

示例代码演示:

public interface ComputerPart {
    void accept(ComputerPartVisitor computerPartVisitor);
}

public class Keyboard implements ComputerPart {
    @Override
    public void accept(ComputerPartVisitor computerPartVisitor) {
        computerPartVisitor.visit(this);
    }
}

public class Monitor implements ComputerPart {
    @Override
    public void accept(ComputerPartVisitor computerPartVisitor) {
        computerPartVisitor.visit(this);
    }
}

public class Mouse implements ComputerPart {
    @Override
    public void accept(ComputerPartVisitor computerPartVisitor) {
        computerPartVisitor.visit(this);
    }
}

public class Computer implements ComputerPart {
    private ComputerPart[] parts;

    public Computer() {
        parts = new ComputerPart[] {new Mouse(), new Keyboard(), new Monitor()};
    }

    @Override
    public void accept(ComputerPartVisitor computerPartVisitor) {
        for (int i = 0; i < parts.length; i++) {
            parts[i].accept(computerPartVisitor);
        }
        computerPartVisitor.visit(this);
    }
}

public interface ComputerPartVisitor {
    void visit(Computer computer);
    void visit(Mouse mouse);
    void visit(Keyboard keyboard);
    void visit(Monitor monitor);
}

public class ComputerPartDisplayVisitor implements ComputerPartVisitor {
    @Override
    public void visit(Computer computer) {
        System.out.println("Displaying Computer");
    }

    @Override
    public void visit(Mouse mouse) {
        System.out.println("Displaying Mouse");
    }

    @Override
    public void visit(Keyboard keyboard) {
        System.out.println("Displaying Keyboard");
    }

    @Override
    public void visit(Monitor monitor) {
        System.out.println("Displaying Monitor");
    }
}

public class Main {
    public static void main(String[] args) {
        ComputerPart computer = new Computer();
        computer.accept(new ComputerPartDisplayVisitor());
        // 输出:
        // Displaying Mouse
        // Displaying Keyboard
        // Displaying Monitor
        // Displaying Computer
    }
}

应用场景:当你需要在不改变被访问的类的前提下,定义一个新的操作,并且这个操作需要遍历一个对象结构时,可以使用访问者模式。比如,在一个文件系统中,可以使用访问者模式来实现对不同类型文件的访问和操作。

22.并发型模式

解释说明:并发型模式就像是程序员的团队协作指南,能够帮助处理多线程环境下的并发操作。它提供了一些常用的并发设计模式和技术,用于解决线程安全、并发控制和线程间通信等问题。

示例代码演示:

// 线程安全的单例模式
public class Singleton {
    private static Singleton instance;

    private Singleton() {}

    public static synchronized Singleton getInstance() {
        if (instance == null) {
            instance = new Singleton();
        }
        return instance;
    }
}

// 线程安全的计数器
public class Counter {
    private int count = 0;

    public synchronized void increment() {
        count++;
    }

    public synchronized void decrement() {
        count--;
    }

    public synchronized int getCount() {
        return count;
    }
}

// 线程间通信
public class Message {
    private String content;
    private boolean isProduced = false;

    public synchronized String getContent() {
        while (!isProduced) {
            try {
                wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        isProduced = false;
        notifyAll();
        return content;
    }

    public synchronized void setContent(String content) {
        while (isProduced) {
            try {
                wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        this.content = content;
        isProduced = true;
        notifyAll();
    }
}

public class Producer implements Runnable {
    private Message message;

    public Producer(Message message) {
        this.message = message;
    }

    @Override
    public void run() {
        String[] messages = {"Hello", "World", "Java"};
        for (String msg : messages) {
            message.setContent(msg);
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        message.setContent("END");
    }
}

public class Consumer implements Runnable {
    private Message message;

    public Consumer(Message message) {
        this.message = message;
    }

    @Override
    public void run() {
        String content = message.getContent();
        while (!content.equals("END")) {
            System.out.println("Received: " + content);
            content = message.getContent();
        }
    }
}

public class Main {
    public static void main(String[] args) {
        Message message = new Message();
        Thread producerThread = new Thread(new Producer(message));
        Thread consumerThread = new Thread(new Consumer(message));

        producerThread.start();
        consumerThread.start();
    }
}

应用场景:当你需要处理多线程环境下的并发操作时,可以使用并发型模式。比如,在多线程的服务器程序中,可以使用并发型模式来实现线程安全的单例模式、线程安全的计数器和线程间的通信。

23.线程池模式

解释说明:线程池模式就像是程序员的任务调度中心,能够复用线程并管理线程的生命周期。它通过维护一定数量的线程池,可以高效地执行多个任务,避免了频繁创建和销毁线程的开销。

示例代码演示:

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class ThreadPoolExample implements Runnable {
    private String taskName;

    public ThreadPoolExample(String taskName) {
        this.taskName = taskName;
    }

    @Override
    public void run() {
        System.out.println("Task " + taskName + " is running");
        try {
            // 模拟任务执行时间
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("Task " + taskName + " is completed");
    }

    public static void main(String[] args) {
        ExecutorService executorService = Executors.newFixedThreadPool(5);

        for (int i = 0; i < 10; i++) {
            Runnable task = new ThreadPoolExample("Task " + (i + 1));
            executorService.execute(task);
        }

        executorService.shutdown();
    }
}

应用场景:当你需要高效地执行多个任务时,可以使用线程池模式。比如,在服务器程序中,可以使用线程池模式来处理并发请求,复用线程并提高任务处理的效率。

在编程的世界里,设计模式是我们的魔法武器,能够帮助我们解决各种复杂的问题,让我们的代码变得更加优雅和可维护。通过学习和应用这些设计模式,我们能够提高代码的重用性、灵活性和可扩展性,使得我们的程序更加健壮和可靠。

不仅如此,设计模式还能够让我们的代码闪耀出独特的光芒。通过合理地运用设计模式,我们可以让代码更加易读、易懂,让其他人能够更轻松地理解和维护我们的代码。设计模式不仅仅是一种技术,更是一种艺术,是我们展示编程能力和智慧的舞台。

正如古人云:“技多不压身,术多不压心。”学习和掌握这些设计模式,并不是为了追求技术的繁杂和复杂,而是为了让我们的代码更加简洁和优雅。设计模式是我们的工具,我们要善于运用它们,而不是被它们束缚。要记住,设计模式是为了服务于我们的需求,而不是为了迎合设计模式。

所以,让我们一起探索设计模式的奇妙世界,用它们来编写酷炫的代码,让我们的程序充满创意和活力。无论是单例模式、工厂模式、装饰器模式,还是观察者模式、策略模式,它们都是我们的利器,帮助我们应对各种编程挑战。

让我们成为那个能够灵活运用设计模式的程序员,用设计模式来点亮我们的编程世界。相信通过不断学习和实践,我们能够编写出更加酷炫和优雅的代码,让我们的程序成为艺术的杰作。

祝愿你在编程的旅途中,能够充满创造力和激情,用设计模式来开启属于你的编程传奇!

作者:Sry0
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0协议。转载请注明文章地址及作者
暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇