Java设计模式

Java设计模式是一组在解决软件设计中常见问题时的经验总结,它们是可重用的解决方案模板,旨在提高代码的可维护性、灵活性和可扩展性。

一、设计模式可以分为三大类

1、创建型模式(Creational Patterns)

1.1、工厂方法模式(Factory Method)

定义一个创建对象的接口,让子类决定实例化哪一个类。

interface Shape {
    void draw();
}

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

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

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

1.2、抽象工厂模式(Abstract Factory)

提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们的具体类。

//假设我们有一个系统需要创建不同类型的GUI组件(按钮和文本框),并且这些组件有多种风格(Windows风格和MacOS风格)。
//首先,定义两个接口,分别代表按钮和文本框:
// GUI组件接口
interface Button {
    void paint();
}

interface TextBox {
    void render();
}


//然后,为每种风格实现这些接口:
// Windows风格的组件
class WindowsButton implements Button {
    @Override
    public void paint() {
        System.out.println("Rendering a Windows button.");
    }
}

class WindowsTextBox implements TextBox {
    @Override
    public void render() {
        System.out.println("Rendering a Windows text box.");
    }
}

// MacOS风格的组件
class MacOSButton implements Button {
    @Override
    public void paint() {
        System.out.println("Rendering a MacOS button.");
    }
}

class MacOSTextBox implements TextBox {
    @Override
    public void render() {
        System.out.println("Rendering a MacOS text box.");
    }
}


//接下来,定义抽象工厂接口和具体工厂类:
// 抽象工厂接口
interface GUIFactory {
    Button createButton();
    TextBox createTextBox();
}

// Windows风格的工厂
class WindowsFactory implements GUIFactory {
    @Override
    public Button createButton() {
        return new WindowsButton();
    }

    @Override
    public TextBox createTextBox() {
        return new WindowsTextBox();
    }
}

// MacOS风格的工厂
class MacOSFactory implements GUIFactory {
    @Override
    public Button createButton() {
        return new MacOSButton();
    }

    @Override
    public TextBox createTextBox() {
        return new MacOSTextBox();
    }
}

//最后,客户端代码可以根据需要选择工厂来创建组件:
public class Client {
    public static void main(String[] args) {
        // 根据操作系统选择工厂
        GUIFactory factory;
        if (System.getProperty("os.name").contains("Windows")) {
            factory = new WindowsFactory();
        } else {
            factory = new MacOSFactory();
        }

        // 创建组件并渲染
        Button button = factory.createButton();
        button.paint();

        TextBox textBox = factory.createTextBox();
        textBox.render();
    }
}

/**
在这个例子中,GUIFactory是一个抽象工厂,它声明了创建GUI组件的接口,而WindowsFactory和MacOSFactory是具体工厂,它们实现了这些接口,用于创建特定风格的组件。客户端代码通过选择合适的工厂来获取与平台相匹配的组件实例,而无需直接关心具体类的创建细节。
**/

1.3、单例模式(Singleton)

保证一个类只有一个实例,并提供一个全局访问点。

public class Singleton {
    private static volatile Singleton instance;

    private Singleton() {}

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

1.4、建造者模式(Builder)

将一个复杂对象的构建与其表示分离,使得同样的构建过程可以创建不同的表示。

/**
建造者模式(Builder Pattern)用于创建复杂的对象,它将对象的构造过程和表示分离,使得构造过程可以有不同的表示。下面是一个简单的Java建造者模式示例,以创建一个汉堡包(Hamburger)为例:
首先,我们定义一个Hamburger类,它代表最终要构建的产品:
**/
public class Hamburger {
    private String bread;
    private String patty;
    private String sauce;
    private String cheese;

    public Hamburger(String bread, String patty, String sauce, String cheese) {
        this.bread = bread;
        this.patty = patty;
        this.sauce = sauce;
        this.cheese = cheese;
    }

    @Override
    public String toString() {
        return "Hamburger{" +
                "bread='" + bread + '\'' +
                ", patty='" + patty + '\'' +
                ", sauce='" + sauce + '\'' +
                ", cheese='" + cheese + '\'' +
                '}';
    }
}

//接着,定义一个HamburgerBuilder接口,它声明了构建汉堡的各个步骤:
public interface HamburgerBuilder {
    HamburgerBuilder withBread(String bread);
    HamburgerBuilder withPatty(String patty);
    HamburgerBuilder withSauce(String sauce);
    HamburgerBuilder withCheese(String cheese);
    Hamburger build();
}
//现在,我们可以创建一个具体的VeggieHamburgerBuilder类,实现HamburgerBuilder接口:
public class VeggieHamburgerBuilder implements HamburgerBuilder {
    private String bread;
    private String patty;
    private String sauce;
    private String cheese;

    @Override
    public HamburgerBuilder withBread(String bread) {
        this.bread = bread;
        return this;
    }

    @Override
    public HamburgerBuilder withPatty(String patty) {
        this.patty = patty;
        return this;
    }

    @Override
    public HamburgerBuilder withSauce(String sauce) {
        this.sauce = sauce;
        return this;
    }

    @Override
    public HamburgerBuilder withCheese(String cheese) {
        this.cheese = cheese;
        return this;
    }

    @Override
    public Hamburger build() {
        return new Hamburger(bread, patty, sauce, cheese);
    }
}

//最后,我们可以创建一个Director类来指导如何使用建造者
public class Director {
    public Hamburger construct(HamburgerBuilder builder) {
        return builder
                .withBread("Whole Wheat")
                .withPatty("Vegetable Patty")
                .withSauce("Tomato Sauce")
                .withCheese("No Cheese") // Vegetarian option
                .build();
    }
}
//客户端代码可以这样使用上述类:
public class Client {
    public static void main(String[] args) {
        HamburgerBuilder builder = new VeggieHamburgerBuilder();
        Director director = new Director();
        Hamburger veggieHamburger = director.construct(builder);

        System.out.println(veggieHamburger);
    }
}
/**
在这个例子中,Director类负责组织建造者的构建步骤,而VeggieHamburgerBuilder则负责具体构建Hamburger对象。这种方式允许我们在不修改Director或Hamburger的情况下,添加新的汉堡类型(如ChickenHamburgerBuilder)。
**/

1.5、原型模式(Prototype)

用原型实例指定创建对象的种类,并通过复制这些原型创建新的对象。       

/**
定义原型接口(可选)
定义一个原型接口来规范所有的原型对象都必须实现clone()方法。
**/
public interface Prototype {
    Prototype clone();
}


/**
实现原型类
接下来,创建一个实现了Cloneable接口并实现了Prototype接口的具体原型类。
这里以一个简单的Shape类为例,假设我们有圆形、方形等形状,它们都可以被复制。
**/
import java.util.Date;

public class Shape implements Cloneable, Prototype {
    
    private String id;
    private Date createdOn;
    
    public Shape() {
        this.createdOn = new Date();
    }
    
    // Getter and Setter methods for id and createdOn
    
    @Override
    public Prototype clone() {
        try {
            return (Prototype) super.clone();
        } catch (CloneNotSupportedException e) {
            throw new AssertionError("Clone should be supported", e);
        }
    }
}

// 具体的形状类,如 Circle 和 Square,继承自 Shape 类并添加各自的属性和方法
class Circle extends Shape {
    private int radius;
    
    // Constructor, getters, and setters for radius
}

class Square extends Shape {
    private int side;
    
    // Constructor, getters, and setters for side
}


/**
客户端代码
客户端代码使用原型对象的clone()方法来创建新的对象实例。
**/
public class Client {
    public static void main(String[] args) {
        Circle circle = new Circle();
        circle.setId("1");
        circle.setRadius(5);
        
        Circle clonedCircle = (Circle) circle.clone();
        System.out.println("Original Circle ID: " + circle.getId());
        System.out.println("Cloned Circle ID: " + clonedCircle.getId());
        // 注意:尽管ID相同,但它们是两个不同的对象,createdOn时间也会不同
    }
}

2、结构型模式(Structural Patterns)

2.1、适配器模式(Adapter)

将一个类的接口转换成客户希望的另一个接口,使得原本不兼容的类可以一起工作。

这种模式涉及到一个单一的类,该类负责加入独立接口到另一个接口中,使得两者能够协同工作。

下面是一个简单的Java适配器模式示例:

/**
*** 其中有一个音频播放器只能播放.mp3文件,但希望它也能播放.wav文件。
*** 为此,创建一个适配器来让.wav文件看起来像.mp3文件。
**/
 
//目标接口(Target Interface)

// 客户端已经期待的接口,即播放器能识别的音频格式
interface MediaPlayer {
    void play(String audioType, String fileName);
}


//适配者类(Adaptee Class)

// 现有的音频播放类,只能播放.wav文件
class AudioPlayer implements MediaPlayer {
    @Override
    public void play(String audioType, String fileName) {
        if ("mp3".equalsIgnoreCase(audioType)) {
            System.out.println("AudioPlayer cannot play this type of file: " + audioType);
        } else if ("wav".equalsIgnoreCase(audioType)) {
            System.out.println("Playing wav file. Name: " + fileName);
        }
    }
}


//适配器类(Adapter Class)

// 适配器类,使AudioPlayer能够播放.mp3文件
class MediaAdapter implements MediaPlayer {
    private final AudioPlayer audioPlayer;

    public MediaAdapter(AudioPlayer audioPlayer) {
        this.audioPlayer = audioPlayer;
    }

    @Override
    public void play(String audioType, String fileName) {
        if ("mp3".equalsIgnoreCase(audioType)) {
            // 将.mp3文件转换为.wav格式,然后调用AudioPlayer的play方法
            fileName = fileName.replace(".mp3", ".wav");
            audioPlayer.play("wav", fileName);
        } else {
            audioPlayer.play(audioType, fileName);
        }
    }
}


//客户端代码(Client Code)
public class AdapterPatternDemo {
    public static void main(String[] args) {
        AudioPlayer audioPlayer = new AudioPlayer();

        // 使用适配器播放.mp3文件
        MediaPlayer mediaAdapter = new MediaAdapter(audioPlayer);
        mediaAdapter.play("mp3", "song.mp3");

       
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值