一天学会23种设计模式


引言:
  学习设计模式之前,我们要知道为什么需要设计模式?想想你在初中、高中时是怎么做数学题的?每遇到一个难题,你不需要重头开始思考解决方法,而是有一定的解题“套路”。设计模式就像是解题的“套路”,一个好的“套路”应该适用于大多数题目,设计模式也是如此,一个好的设计模式不仅可以解决目前的问题,还可以很好地应对将来的变化。对于Java而言,只有运用好设计模式才能迈进J2EE的门槛。 用一句话概括:设计模式就是为了提高代码的复用性,降低程序的耦合。

A. 创建模式

  创建模式用于提供创建对象的机制

1. 单例模式(Singleton)

  单例模式的目的是保证一个类只有一个实例,并且提供一个接口使用该实例。
  最佳实践:建立目录;建立数据库连接。
  一般单例模式通常有两种形式:饿汉式、懒汉式。

//饿汉式,在类的加载阶段就会创建该类的实例对象
public class girlFriend {
    private String name;
    private girlFriend(String name){
        this.name = name;
    }
    private static girlFriend gf = new girlFriend("gf");
    public static girlFriend getInstance(){
        return gf;
    }
}
//懒汉式,在类的初始化阶段创建该类的实例对象
public class girlFriend {
    private String name;
    private girlFriend(String name) {
        this.name = name;
    }
    private static girlFriend gf = null;
    public static synchronized girlFriend getInstance() {
        if(gf == null){
            gf = new girlFriend("gf");
        }
        return gf;
    }
}

懒汉式和饿汉式的区别:

  • 创建对象时机不同。
  • 懒汉式是线程不安全的,需要加锁;饿汉式是线程安全的。

2. 工厂模式(Factory)

  工厂模式用于创建实例对象,一般有三种形式:简单工厂模式、工厂模式、抽象工厂模式。
  最佳实践:对象创建需要重用;未知该类需要创建多少子类对象
  ①简单工厂模式:核心工厂根据不同参数创建不同的对象(直接生产产品)。

public class simpleFactory {
    public static product createProduct(int type) {
        if(type == 1) {
            return new product1();
        } else if(type == 2){
            return new product2();
        }
        return null;
    }
    public static void main(String[] args) {
        product product1 = simpleFactory.createProduct(1);
        product1.print();
    }
}

abstract class product{
    public abstract void print();
}

class product1 extends product{
    public void print(){
        System.out.println("产品1");
    }
}

class product2 extends product{
    public void print(){
        System.out.println("产品2");
    }
}

  ②工厂模式:核心工厂的子类决定生产产品。核心工厂只需要定义创建对象的接口,这样可以使类的实例化延迟到其子类。

public class factory {
    public static void main(String[] args) {
        productFactory p1f = new product1Factory();
        product p = p1f.getProduct();
        p.print();
    }
}

interface product{
    void print();
}

interface productFactory{
    product getProduct();
}

class product1 implements product{
    public void print(){
        System.out.println("产品1");
    }
}

class product2 implements product{
    public void print(){
        System.out.println("产品2");
    }
}

class product1Factory implements productFactory{
    @Override
    public product getProduct(){
        return new product1();
    }
}

class product2Factory implements productFactory{
    @Override
    public product getProduct(){
        return new product2();
    }
}

  ③抽象工厂模式:具体工厂类可以创建多个对象。

public class factory {
    public static void main(String[] args) {
        specificFactory sf = new specificFactory();
        Computer legion = sf.getLegionComputer();
        Phone apple = sf.getApplePhone();
        legion.print();
        apple.print();
    }
}

//产品1->电脑
interface Computer{
    void print();
}
class legion implements Computer{
    @Override
    public void print() {
        System.out.println("legion");
    }
}

//产品2->手机
interface Phone{
    void print();
}
class apple implements Phone{
    @Override
    public void print() {
        System.out.println("apple");
    }
};

//抽象工厂
interface abstractFactory{
    Computer getLegionComputer();
    Phone getApplePhone();
}

//具体工厂
class specificFactory implements abstractFactory{
    @Override
    public Computer getLegionComputer() {
        return new legion();
    }
    @Override
    public Phone getApplePhone() {
        return new apple();
    }
}

3. 建造者模式(Builder)

  建造者模式适用于将一个复杂对象的构建与表示分离,使得同样的构建过程可以创建不同的对象,解耦过程与产品。
  经典的Builder模式用Builder接口定义如何创建复杂对象,用Director类构建最后的复杂对象,即组装最后成品。
  最佳实践:创建属性很多的复杂对象,以下代码实现(最佳实践中并没有使用到Director类构建最后的对象,而是通过链式结构控制构建过程;也没有单独定义Builder接口,而是使用静态内部类代替Builder接口的实现类。这也说明了设计模式不是原封不动地套用,需要开发者在实践中具体问题具体分析)。

// Person类->含有很多字段的复杂对象
class Person {
    private String name;
    private int age;
    private String gender;
    private String address;
    private String phone;
    private String email;
    private int id;
    private String password;
    private String city;
    private String state;
    private Person(){}
    public static class personBuilder{ // 静态内部类,代替了Builder接口的实现类
        Person p = new Person();
        public personBuilder setInfo(String name, int age, String gender){
            p.name = name;
            p.age = age;
            p.gender = gender;
            return this;
        }
        public personBuilder setAddress(String address){
            p.address = address;
            return this;
        }
        public personBuilder setPhone(String phone){
            p.phone = phone;
            return this;
        }
        public personBuilder setAccount(int id, String password, String email, String state){
            p.id = id;
            p.password = password;
            p.email = email;
            p.state = state;
            return this;
        }
        public personBuilder setCity(String city){
            p.city = city;
            return this;
        }
        public Person build(){
            return p;
        }
    }

    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", gender='" + gender + '\'' +
                ", address='" + address + '\'' +
                ", phone='" + phone + '\'' +
                ", email='" + email + '\'' +
                ", id=" + id +
                ", password='" + password + '\'' +
                ", city='" + city + '\'' +
                ", state='" + state + '\'' +
                '}';
    }
}

public class Builder{
    public static void main(String[] args) {
     	//链式结构构建对象,代替Director类功能
        Person p = new Person.personBuilder()
                .setInfo("wistain", 22, "male")
                .setAccount(1, "123", "123456@qq.com", "在职")
                .build();
        System.out.println(p);
    }
}

4. 原型模式(Prototype)

  用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象。
  在实际项目中,原型模式很少单独出现,一般是和工厂方法模式一起出现,通过 clone 的方法创建一个对象,然后由工厂方法提供给调用者(下面第二段代码演示)。
  最佳实践:new一个对象需要非常复杂的数据准备(类初始化消耗大量资源);一个对象有多线程使用并修改。

//不使用java提供的clone()方法
interface protoType{
    Object clone();
}

class Sheep implements protoType{
    private String name;
    private String id;
    public Sheep(){
        name = "dolly's father";
        id = String.valueOf(Math.random());
    }
    public Sheep(Sheep sheep){
        this.name = sheep.name;
        this.id = sheep.id;
    }
    public void getName(){
        System.out.println(name);
    }
    public void getId(){
        System.out.println(id);
    }
    @Override
    public Object clone() {
        return new Sheep(this);
    }
}

public class protoTypePattern{
    public static void main(String[] args){
        Sheep sheep = new Sheep();
        sheep.getName();
        sheep.getId();
        System.out.println(sheep);
        Sheep dolly = (Sheep)sheep.clone();
        dolly.getName();
        dolly.getId();
        System.out.println(dolly);
    }
}
//使用java提供的clone()方法并结合工厂模式
abstract class AbstractSheep implements Cloneable {
    private String name;
    public Object clone() {
        Object object = null;
        try {
            object = super.clone();
        } catch (CloneNotSupportedException exception) {
            System.out.println("AbstractSheep is not Cloneable");
        }
        return object;
    }
}

interface Factory{
    Sheep createSheep(Sheep sheep);
}

class cloneFactory implements Factory{
    @Override
    public Sheep createSheep(Sheep sheep) {
        return (Sheep)sheep.clone();
    }
}

class Sheep extends AbstractSheep{
    private String name;
    public Sheep(String name) {
        this.name = name + (char)(Math.random() * 100);
    }
    public String getName() {
        return name;
    }
}

public class protoTypePattern {
    public static void main(String[] args) {
        Factory factory = new cloneFactory();
        Sheep sheep = new Sheep("Dolly");
        Sheep dolly = factory.createSheep(sheep);
        System.out.println("羊的名字:" + sheep.getName());
        System.out.println("羊的地址:" + sheep.hashCode());
        System.out.println("克隆羊的名字:" + dolly.getName());
        System.out.println("克隆羊的地址:" + dolly.hashCode());
    }
}

B. 结构模式

  结构模式通过继承和组合,构建出更加复杂的结构,从而提供更加强大的逻辑功能

1. 适配器模式(Adapter)

  适配器模式用于将一个类的接口变换成客户端所期待的另一种接口,从而使原本因接口不匹配而无法在一起工作的两个类能够在一起工作。

class Circle{
    public String insert(){
        return "接入圆形接口";
    }
}

interface circleToSquare{
    public String circleToSquare();
}

class Adapter implements circleToSquare{
    private Circle circle;
    public Adapter(Circle circle){
        this.circle = circle;
    }
    @Override
    public String circleToSquare() {
        String res = circle.insert();
        res += "->接入方形接口";
        return res;
    }
}

public class adapterPattern{
    public static void main(String[] args) {
        Circle circle = new Circle();
        circleToSquare cts = new Adapter(circle);
        System.out.println(cts.circleToSquare());
    }
}

2. 代理模式(Proxy)

  代理模式就是为其他对象提供一种代理以控制对这个对象的访问。
  最佳实践:授权机制,不同级别的用户对同一对象拥有不同的访问权利。如 Jive 论坛系统中,就使用 Proxy 进行授权机制控制,访问论坛有两种人:注册用户和游客(未注册用户),Jive 中就通过类似 ForumProxy 这样的代理来控制这两种用户对论坛的访问权限。

interface foreignWeb {
	public String show();
}

class Google implements foreignWeb{
	@Override
	public String show() {
		return "Google页面";
	}
}

class scientificTool implements foreignWeb{
	//通过scientificTool国外服务器获得Google页面
	public scientificTool(){
		System.out.println("通过scientificTool国外服务器获得Google页面");
	}
	Google google = new Google();
	String googlePage = google.show();

	@Override
	public String show() {
		return googlePage;
	}
}

public class client {
	public static void main(String[] args) {
		scientificTool scientifictool = new scientificTool();
		System.out.println("访问scientificTool国内服务器");
		System.out.println("展示:" + scientifictool.show());
	}
}

3. 外观模式(Facade)

  为子系统中的一组接口提供一个一致的界面。
  最佳实践:数据库JDBC,所有程序对数据库访问都是使用改接口,降低系统的复杂性,增加了灵活性。
  在下例代码中,电脑computerFacade为各个子系统提供了一致的界面,定义了一个高层接口,这个接口使得这一子系统更加容易使用。客户只要调用这一个接口而不用调用多个接口就能达到目的,也不需关心这个子系统的内部细节。

class Screen {
	private static Screen screen = null;
	public static synchronized Screen getInstance() {
		if (screen == null) {
			screen = new Screen();
		}
		return screen;
	}
	public void on() {
		System.out.println("启动屏幕");
	}
	public void off() {
		System.out.println("关闭屏幕");
	}
}

class CPU {
	private static CPU cpu = null;
	public static synchronized CPU getInstance() {
		if (cpu == null) {
			cpu = new CPU();
		}
		return cpu;
	}
	public void on() {
		System.out.println("启动处理器");
	}
	public void off() {
		System.out.println("关闭处理器");
	}
}

class GPU {
	private static GPU gpu = null;
	public static synchronized GPU getInstance() {
		if (gpu == null) {
			gpu = new GPU();
		}
		return gpu;
	}
	public void on() {
		System.out.println("启动显示适配器");
	}
	public void off() {
		System.out.println("关闭显示适配器");
	}
}

class computerFacade {
	CPU cpu = CPU.getInstance();
	GPU gpu = GPU.getInstance();
	Screen screen = Screen.getInstance();
	public void powerOn() {
		cpu.on();
		gpu.on();
		screen.on();
	}
	public void shutDown() {
		cpu.off();
		gpu.off();
		screen.off();
	}
}

public class Client {
	public static void main(String[] args) {
		computerFacade computer = new computerFacade();
		System.out.println("---启动电脑---");
		computer.powerOn();
		System.out.println("---关闭电脑---");
		computer.shutDown();
	}
}

4. 组合模式(Composite)

  将对象以树形结构组织起来,达成“部分—整体”的层次结构,使得客户端对单个对象和组合对象的使用具有一致性。
  最佳实践:贴吧中主题帖与回帖构成树形结构关系。
  以公司的结构为例,CEO(首席执行官)和副总裁(VP)在同一层中;部门1包含在公司中,部门1中有COO(首席运营官)、CFO(首席财务官)、CTO(首席技术官)等;部门1中又包含了部门2,部门2又director(总监)等等,以此类推。
公司
├── CEO(首席执行官)
│ ├── 首席运营官(COO)
│ │ ├── 总监
│ │ └── …
│ ├── 首席财务官(CFO)
│ │ └── …
│ ├── 首席技术官(CTO)
│ │ └── …
├── VP(副总裁)
  └── …

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

interface Printer {
	void print();
}

// 叶子结点
class Position implements Printer{
	private String position;
	public Position(String position) {
		this.position = position;
	}
	@Override
	public void print() {
		System.out.println("我的职位是" + position);
	}
	
}

// 容器类
class Composite implements Printer{
	private List<Printer> positionList = new ArrayList<>();
	public void add(Printer printer) {
		positionList.add(printer);		
	}
	public void delete(Printer printer) {
		positionList.remove(printer);
	}
	public List<Printer> getChild(){
		return positionList;
	}
	@Override
	public void print() {
		for(Printer printer : positionList) {
			printer.print();
		}
	}
	
}

public class compositePattern {
	public static void main(String[] args) {
		Composite googleCompany = new Composite();
		googleCompany.add(new Position("CEO"));
		googleCompany.add(new Position("VP"));
		Composite firstDepartment = new Composite();
		googleCompany.add(firstDepartment);
		firstDepartment.add(new Position("COO"));
		firstDepartment.add(new Position("CFO"));
		firstDepartment.add(new Position("CTO"));
		Composite secondDepartment = new Composite();
		googleCompany.add(secondDepartment);
		secondDepartment.add(new Position("director"));
		googleCompany.print();
	}
}

5. 装饰器模式(Decorator)

  动态地给一个对象添加一些额外的功能,这些功能由用户决定加入的方式和时机。Decorator提供了“即插即用”的方法,在运行期间决定何时增加何种功能。
  最佳实践:IO流中的FilterInputStream。
  以下示例很形象,码农秒懂!

// 描述功能接口
public interface Work {
	void writeCode();
}

//接口的实现类,Decoratee(装饰者)
class Programmer implements Work{
	@Override
	public void writeCode() {
		System.out.println("写代码");
	}
}

//Decorator(装饰器)
class Decorator implements Work{
	Programmer programmer;
	public Decorator(Programmer programmer) {
		this.programmer = programmer;
	}
	@Override
	public void writeCode() {
		programmer.writeCode();
	}
	public void moreWork() {
		programmer.writeCode();
		System.out.println("996");
	}
}

public class decoratorPattern {
	public static void main(String[] args) {
		new Decorator(new Programmer()).moreWork();
	}
}

6. 桥接模式(Bridge)

  将抽象和行为划分开,各自独立并且能动态地结合。
  最佳实践:Java Beans中的DAO层(Data Access Object),为了使逻辑与具体数据资源分开,将操作数据库的行为独立抽象成一个行为接口DAO。

// 抽象接口
abstract class Coffee {
	private coffeeImpl coffeeimpl;
	public void setCoffeeImpl() {
		this.coffeeimpl = coffeeImplSingleton.getCoffeeImpl();
	}
	public coffeeImpl getCoffeeImpl() {
		return this.coffeeimpl;
	}
	public abstract void pourCoffee();
}

// 行为接口
interface coffeeImpl {
	void pourCoffeeImpl();
}

// 抽象接口的实现类1—>中杯咖啡
class mediumCoffee extends Coffee{
	public mediumCoffee() {
		setCoffeeImpl();
	}
	@Override
	public void pourCoffee() {
		coffeeImpl coffeeimpl = this.getCoffeeImpl();
		for (int i = 0; i < 2; i++) {
			coffeeimpl.pourCoffeeImpl();
		}
		System.out.println("-----中杯咖啡制作完成-----");
	}
}

// 抽象接口的实现类2—>大杯咖啡
class largeCoffee extends Coffee{
	public largeCoffee() {
		setCoffeeImpl();
	}

	@Override
	public void pourCoffee() {
		coffeeImpl coffeeimpl = this.getCoffeeImpl();
		for (int i = 0; i < 3; i++) {
			coffeeimpl.pourCoffeeImpl();
		}
		System.out.println("-----大杯咖啡制作完成-----");
	}
}

// 行为接口的实现类1—>加牛奶
class milkCoffeeImpl implements coffeeImpl{
	@Override
	public void pourCoffeeImpl() {
		System.out.println("加入牛奶");
	}
}

//行为接口的实现类2->加茶
class teaCoffeeImpl implements coffeeImpl{
	@Override
	public void pourCoffeeImpl() {
		System.out.println("加入茶");
	}
}

// Singleton类,用于提供当前的coffeeImpl
class coffeeImplSingleton {
	private static coffeeImpl coffeeimpl;
	public coffeeImplSingleton(coffeeImpl coffeeimpl) {
		this.coffeeimpl = coffeeimpl;
	}
	public static coffeeImpl getCoffeeImpl() {
		return coffeeimpl;
	}
}

// 主类
public class bridgePattern {
	public static void main(String[] args) {
		coffeeImplSingleton coffeeimplsingleton = new coffeeImplSingleton(new milkCoffeeImpl());
		mediumCoffee mediumcoffee = new mediumCoffee();
		mediumcoffee.pourCoffee();
		coffeeimplsingleton = new coffeeImplSingleton(new teaCoffeeImpl());
		largeCoffee largecoffee = new largeCoffee();
		largecoffee.pourCoffee();
	}
}

7. 享元模式(Flyweight)

  避免大量拥有相同内容的小类的开销,使大家共享一个类。
  最佳实践:池技术,如字符串常量池、线程池等。

import java.util.HashSet;
import java.util.Set;

abstract class bankFlyWeight {
	// 内部状态
	protected Boolean state = false; // false表示没有人在该柜台办理业务,true表示有人在该柜台办理业务
	// name就是外部状态
	abstract void handle(String name);
	abstract void free();
	
	public Boolean getState() {
		return state;
	}
}

// 负责维护一个FlyWeight池,客户端请求一个共享 Flyweight 时,首先搜索池中是否有可用的
class bankFlyWeightFactory {
	private static bankFlyWeightFactory instance = null;
	public static synchronized bankFlyWeightFactory getInstance() {
		if(instance == null) {
			instance = new bankFlyWeightFactory();
		}
		return instance;
	}
	private Set<bankFlyWeight> counterPool = new HashSet<>();
	private bankFlyWeightFactory() {
		for (int i = 0; i < 2; i++) {
			counterPool.add(new Counter(i));
		}
	}
	public bankFlyWeight getCounter() {
		for (bankFlyWeight counter : counterPool) {
			if(counter.state == false)
				return counter;
		}
		return null;
	}
}

class Counter extends bankFlyWeight{
	private int id;
	public Counter(int id) {
		this.id = id;
	}
	@Override
	void handle(String name) {
		if(state == true) {
			System.out.println("第" + id + "号柜台繁忙,请等待...");
		} else {
			state = true;
			System.out.println(name + "正在第"+ id + "号柜台办理业务...");
		}
	}

	@Override
	void free() {
		state = false;
		System.out.println("第" + id + "号柜台业务办理结束");
	}
}

public class flyWeightPattern {
	public static void main(String[] args) {
		bankFlyWeight counter1 = bankFlyWeightFactory.getInstance().getCounter();
		counter1.handle("张三");
		bankFlyWeight counter2 = bankFlyWeightFactory.getInstance().getCounter();
		counter2.handle("李四");
		counter1.handle("王五");
		counter2.free();
		bankFlyWeight counter3 = bankFlyWeightFactory.getInstance().getCounter();
		counter3.handle("王五");
		counter1.free();
		counter3.free();
		System.out.println(counter2 == counter3); // true
	}
}

C. 行为模式

  行为模式关注的是对象之间的通信和交互。用于解决特定场景下的行为问题,使得程序中的对象能够更好地协作。

1. 命令模式(Command)

  将请求转换为一个包含与请求相关的所有信息的独立对象。该转换可以让你根据不同的请求将方法参数化、延迟执行或将其放入队列中,且能实现撤销操作。
  以遥控器与电视为例,遥控器上的每个按钮代表一个命令对象,如“调整音量”、“切换频道”等。当用户按下遥控器上的按钮时,实际上是在执行一个命令对象,该对象包含了要执行的操作(即发送一个信号给电视)。电视接收到信号后,执行相应的操作,如增加音量或切换频道。

// 抽象命令接口,定义执行操作的统一方法
interface Command {
	// 调整音量
	void changeVolume();
	// 切换频道
	void changeChannel();
}

// 接收者(执行实际命令的类),命令对象会调用接收者的方法来执行请求。
class Television {
	public void volumeUp() {
		System.out.println("增加电视机音量");
	}
	public void volumeDown() {
		System.out.println("降低电视机音量");
	}
	public void channelForward() {
		System.out.println("电视频道向前");
	}
	public void channelBack() {
		System.out.println("电视频道向后");
	}
}

// 具体命令类,拥有接收者对象,并通过调用接收者的功能来完成命令要执行的操作。
class signalCommand implements Command{
	private Television television;
	public signalCommand(Television television) {
		this.television = television;
	}
	@Override
	public void changeVolume() {
		television.volumeUp();
		television.volumeDown();
	}
	@Override
	public void changeChannel() {
		television.channelForward();
		television.channelBack();
	}
}

// 调用者,持有命令对象(通常是多个)并通过访问命令对象来执行相关请求,他不直接访问接收者。
class Remote {
	private Command command;
	public Remote(Command command) {
		this.command = command;
	}
	public void changeVolumeCommand() {
		System.out.println("用户按下调整音量按钮");
		command.changeVolume();
	}
	public void changeChannelCommand() {
		System.out.println("用户按下更换频道按钮");
		command.changeChannel();
	}
}

// 主类
public class commandPattern {
	public static void main(String[] args) {
		Television television = new Television();
		Command command = new signalCommand(television);
		Remote remote = new Remote(command);
		remote.changeChannelCommand();
		remote.changeVolumeCommand();
	}
}

2. 观察者模式(Observer)

  定义对象间的一种一对多依赖关系,使得每当一个对象状态发生改变时,其相关依赖对象都会得到通知并自动更新。
  最佳实践:网上商店中商品信息有变化,系统自动通知会员。
  以最佳实践为例,观察者接口定义了关注商品和提醒订阅者的方法,订阅者接口定义了接收消息的方法;网上商店实现了观察者接口,获得所有订阅者的引用并且设置了商品状态,一旦商品状态改变就会调用提醒订阅者的方法;用户类实现了订阅者接口。

import java.util.HashSet;
import java.util.Set;

interface goodsObserver {
	void subscribe(Subscriber subscriber);
	void notifySubscriber();
}

interface Subscriber {
	void receiveMessage();
}

class TaobaoStore implements goodsObserver{
	private Set<Subscriber> allSubscribers = new HashSet<>();
	private Integer state = 0;
	public void setState(Integer state) {
		this.state = state;
		this.notifySubscriber();
	}

	@Override
	public void subscribe(Subscriber subscriber) {
		allSubscribers.add(subscriber);
	}

	@Override
	public void notifySubscriber() {
		for(Subscriber s : allSubscribers) {
			s.receiveMessage();
		}
	}
}
class TaobaoUser implements Subscriber{
	private String name;
	public TaobaoUser(String name) {
		this.name = name;
	}
	@Override
	public void receiveMessage() {
		System.out.println(name + ",您关注的商品信息更新了!");
	}

}

public class observerPattern {
	public static void main(String[] args) {
		TaobaoStore tbStore = new TaobaoStore();
		TaobaoUser Zhangsan = new TaobaoUser("张三");
		TaobaoUser Lisi = new TaobaoUser("李四");
		tbStore.subscribe(Zhangsan);
		tbStore.subscribe(Lisi);
		tbStore.setState(0);
	}
}

3. 迭代器模式(Iterator)

  这个模式已经被整合入Java的Collection类中,在大多数场景下无需自己创造一个Iterator,只要将对象装入Collection中,直接使用Iterator进行对象遍历。

4. 模板模式(Template)

  定义一个操作中算法的框架,将一些步骤延迟到子类中。

// 抽象类好处:扩展性强,method()内容变化只需要再继承一个子类即可
abstract class countTime {
	public abstract void method();
	public final long repeat(int count) {
		if(count <= 0)
			return 0;
		else {
			long startTime = System.currentTimeMillis();
			for (int i = 0; i < count; i++) {
				method();
			}
			long endTime = System.currentTimeMillis();
			return endTime - startTime;
		}
	}
}

class Execute extends countTime{
	@Override
	public void method() {
		for (int i = 0; i < 100000; i++) {
			System.out.println("i = " + i);
		}
	}
}

public class templatePattern {
	public static void main(String[] args) {
		Execute execute = new Execute();
		System.out.println(execute.repeat(2) + "ms");
	}
}

5. 策略模式(Strategy)

  定义一组算法,将每个算法都封装起来,并且使它们之间可以互换。策略模式让算法独立于使用它的客户而变化。
  当你需要从家到公司上班时,你可能会根据天气、交通状况、时间紧迫程度等因素选择不同的出行方式(如步行、骑自行车、乘坐公交等)。每种出行方式都代表了一种策略,可以根据具体情况灵活选择。

interface TravelStrategy {
	void travel();
}

class WalkStrategy implements TravelStrategy{
	@Override
	public void travel() {
		System.out.println("走路出行");
	}
}

class BikeStrategy implements TravelStrategy{
	@Override
	public void travel() {
		System.out.println("骑自行车出行");
	}
}

class BusStrategy implements TravelStrategy{
	@Override
	public void travel() {
		System.out.println("乘坐公交车出行");
	}
}

class TravelAlgorithm {
	private TravelStrategy travelStrategy;
	public TravelAlgorithm(TravelStrategy travelStrategy) {
		this.travelStrategy = travelStrategy;
	}
	public void setStrategy(TravelStrategy travelStrategy) {
		this.travelStrategy = travelStrategy;
		System.out.println("重新设定了出行策略");
	}
	public void executeStrategy() {
		travelStrategy.travel();
	}
}

public class StrategyPattern {
	public static void main(String[] args) {
		TravelAlgorithm travelAlgorithm = new TravelAlgorithm(new WalkStrategy());
		travelAlgorithm.executeStrategy();
		travelAlgorithm.setStrategy(new BikeStrategy());
		travelAlgorithm.executeStrategy();
		travelAlgorithm.setStrategy(new BusStrategy());
		travelAlgorithm.executeStrategy();
	}
}

6. 责任链模式(Chain of Responsibility)

  责任链模式是一种处理请求的模式,它让多个处理器都有机会处理该请求,直到其中某个处理成功为止。
  责任链模式把多个处理器串成链,然后让请求在链上传递。

abstract class Handler {
    protected Handler nextHandler;
    public void setNextHandler(Handler nextHandler){
        this.nextHandler = nextHandler;
    }
    public abstract void process(Integer info);
}

class Leader extends Handler{
    @Override
    public void process(Integer info) {
        if(info > 0 && info < 11){
            System.out.println("Leader处理了:" + info + "级消息");
        } else {
            nextHandler.process(info);
        }
    }
}

class Boss extends Handler {
    @Override
    public void process(Integer info) {
        System.out.println("Boss处理了:" + info + "级消息");
    }
}

public class CoRPattern {
    public static void main(String[] args) {
        Handler level1 = new Leader();
        Handler level2 = new Boss();
        level1.setNextHandler(level2);
        level1.process(1);
        level1.process(11);
    }
}

7. 中介者模式(Mediator)

  用一个对象作为中介,封装一系列关于不同对象的交互行为。
  该模式为了减少对象之间混乱无序的依赖关系,会限制对象之间的直接交互,迫使它们通过一个中介者对象进行合作。
  最佳实践:聊天软件的信息传递。
  使用中介者模式来设计一个基本的社交网络功能。在这个示例中有三个角色:User(用户),Post(帖子),和SocialMediaPlatform(社交媒体平台,作为中介者)。SocialMediaPlatform作为中介者管理着User之间的通信,当一个User发送一个Post时,SocialMediaPlatform负责将这个Post广播给所有其他用户(除了发帖者自己)。这样,用户之间的直接交互被中介者所管理,降低了它们之间的耦合度。

import java.util.ArrayList;
import java.util.List;
// User类包含用户的基本信息和发布帖子的功能
class User{
    private String name;
    public User(String name){
        this.name = name;
    }
    public void sendPost(String message, SocialMediaPlatform socialMediaPlatform){
        Post post = new Post(this, message);
        socialMediaPlatform.broadcastPost(post);
    }
    public String getName(){
        return name;
    }
}

// 帖子
class Post {
    private User author;
    private String message;
    public Post(User author, String message) {
        this.author = author;
        this.message = message;
    }
    public User getAuthor() {
        return author;
    }
    public String getMessage() {
        return message;
    }
}

class SocialMediaPlatform {
    List<User> list = new ArrayList<>();
    public void addUser(User user) {
        list.add(user);
    }
    public void broadcastPost(Post post) {
        for (User user : list) {
            if(!user.equals(post.getAuthor())) {
                notifyUser(user, post);
            }
        }
    }
    private void notifyUser(User user, Post post) {
        System.out.println(user.getName() + " received a post from " + post.getAuthor().getName() + ": " + post.getMessage());
    }
}

public class MediatorPattern {
    public static void main(String[] args) {
        SocialMediaPlatform socialMediaPlatform = new SocialMediaPlatform();
        User zhangsan = new User("Zhangsan");
        User lisi = new User("Lisi");
        User wangwu = new User("Wangwu");
        socialMediaPlatform.addUser(zhangsan);
        socialMediaPlatform.addUser(lisi);
        socialMediaPlatform.addUser(wangwu);
        zhangsan.sendPost("Hello World", socialMediaPlatform);
    }
}

8. 状态模式(State)

  允许一个对象在其内部状态改变时改变它的行为,每个状态都有相应的行为。
  最佳实践:TCP连接过程中的状态;账号的状态等。
  以交通信号灯为例,它有三种状态:红灯、绿灯和黄灯,每种状态都对应着不同的行为:红灯停、绿灯行和黄灯准备停。信号灯会根据预设的时间间隔自动切换状态。状态模式需要两种类型实体参与:状态管理器(Context)和状态的抽象类/接口。我们定义一个TrafficLight类作为Context,它包含当前的状态(红灯、绿灯、黄灯),并允许状态之间的转换。同时,定义三个状态类(RedLightState、GreenLightState、YellowLightState)来实现不同的状态行为。

interface TrafficLightState {
    void changeLight(TrafficLight trafficLight);
}

class RedLightState implements TrafficLightState{
    @Override
    public void changeLight(TrafficLight trafficLight) {
        System.out.println("现在是红灯,停车");
        trafficLight.setState(trafficLight.getGreenLightState());
    }
}

class YellowLightState implements TrafficLightState{
    @Override
    public void changeLight(TrafficLight trafficLight) {
        System.out.println("现在是黄灯,准备停车");
        trafficLight.setState(trafficLight.getRedLightState());
    }
}

class GreenLightState implements TrafficLightState{
    @Override
    public void changeLight(TrafficLight trafficLight) {
        System.out.println("现在是绿灯,前行");
        trafficLight.setState(trafficLight.getYellowLightState());
    }
}

class TrafficLight {
    private TrafficLightState redLightState;
    private TrafficLightState greenLightState;
    private TrafficLightState yellowLightState;
    private TrafficLightState currentLightState;
    public TrafficLight() {
        redLightState = new RedLightState();
        greenLightState = new GreenLightState();
        yellowLightState = new YellowLightState();
        currentLightState = redLightState; // 初始状态为红灯
    }
    public void setState(TrafficLightState state) {
        currentLightState = state;
    }

    public TrafficLightState getRedLightState() {
        return redLightState;
    }

    public TrafficLightState getGreenLightState() {
        return greenLightState;
    }

    public TrafficLightState getYellowLightState() {
        return yellowLightState;
    }

    public void timePass(){
        currentLightState.changeLight(this);
    }
}

public class StatePattern {
    public static void main(String[] args) {
        TrafficLight trafficLight = new TrafficLight();
        for (int i = 0; i < 10; i++) {
            trafficLight.timePass();
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e){
                e.printStackTrace();
            }
        }
    }
}

9. 备忘录模式(Memento)

  备忘录模式可以在不暴露对象实现细节的情况下保存和恢复对象之前的状态。
  memento是一个保存另外一个对象内部状态拷贝的对象。这样以后就可以将该对象恢复到原先保存的状态.

import java.util.Stack;

// 备忘录接口
interface Memento {
    // 定义元数据内容
}

// 备忘录类
class Backup implements Memento{
    String text;
    public Backup(String text) {
        this.text = text;
    }
}

// 文档类,需要使用备忘录恢复
class Document {
    private String text; // 私有化属性,只有本类可以访问
    public Backup save(){
        return new Backup(text); // 提供访问属性的接口
    }
    public void resume(Backup backup){
        text = backup.text;
    }
    public void change(String text){
        this.text = text;
    }
    public void print(){
        System.out.println(text);
    }
}

// 备忘录栈
class DocumentHistory {
    Stack<Backup> backupStack = new Stack<>();
    public void add(Backup backup) {
        backupStack.push(backup);
    }
    public Backup getLastVersion(){
        return backupStack.pop();
    }
}

public class MementoPattern {
    public static void main(String[] args) {
        DocumentHistory documentHistory = new DocumentHistory();
        Document document = new Document();
        document.change("first input");
        documentHistory.add(document.save());
        document.change("second input");
        documentHistory.add(document.save());
        document.resume(documentHistory.getLastVersion());
        document.print();
        document.resume(documentHistory.getLastVersion());
        document.print();
    }
}

10. 解释器模式(Interpreter)

  定义一个语言的文法,并且建立一个解释器来解释该语言中的句子(语言指的是使用规定格式和语法的代码)。
  以烹饪食谱为例,食谱是一种语言的表示,它包含了烹饪食物的步骤、所需的食材和烹饪方法等。厨师则是这种语言的解释器,他们阅读食谱,理解其中的指令,并按照这些指令准备和烹饪食物。我们需要定义一个抽象的解释器接口或抽象类,它包含了解释食谱指令的方法。然后,我们可以为不同的烹饪动作创建具体的解释器类。

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

interface Interpreter {
    void interpret(String context);
}

class CutInterpreter implements Interpreter{
    @Override
    public void interpret(String context) {
        System.out.println("切" + context);
    }
}

class FryInterpreter implements Interpreter{
    @Override
    public void interpret(String context) {
        System.out.println("炒" + context);
    }
}

class BoilInterpreter implements Interpreter{
    @Override
    public void interpret(String context) {
        System.out.println("煮" + context);
    }
}

// 上下文类,用于存储食谱的当前状态或全局信息
class RecipeContext {
    public String name = "血旺";
}

class Recipe {
    private List<Interpreter> steps = new ArrayList<>();
    public void addStep(Interpreter step) {
        steps.add(step);
    }
    public void execute(){
        RecipeContext recipeContext = new RecipeContext();
        for (Interpreter step : steps) {
            step.interpret(recipeContext.name);
        }
    }
}

public class InterpreterPattern {
    public static void main(String[] args) {
        Recipe recipe = new Recipe();
        recipe.addStep(new CutInterpreter());
        recipe.addStep(new FryInterpreter());
        recipe.addStep(new BoilInterpreter());
        recipe.execute();
    }
}

11. 访问者模式(Visitor)

  封装一些作用于某种数据结构中各元素的操作,它可以在不改变数据结构的前提下定义作用于这些元素的新操作。
  在电商网站的商品分类场景中,我们可以将访问者模式应用于不同类型的商品上,以实现对这些商品的不同操作,如打折、购买等。

package VisitorPattern;

interface Product {
    void accept(Visitor visitor);
}

class ClothesProduct implements Product{
    private String name;
    private double price;
    public ClothesProduct(String name, double price) {
        this.name = name;
        this.price = price;
    }
    @Override
    public void accept(Visitor visitor) {
        visitor.visit(this);
    }
    public String getName() {
        return name;
    }
    public double getPrice() {
        return price;
    }
}

class DigitalProduct implements Product{
    private String name;
    private double price;
    public DigitalProduct(String name, double price) {
        this.name = name;
        this.price = price;
    }
    @Override
    public void accept(Visitor visitor) {
        visitor.visit(this);
    }
    public String getName() {
        return name;
    }
    public double getPrice() {
        return price;
    }
}

interface Visitor {
    void visit(DigitalProduct digitalProduct);
    void visit(ClothesProduct clothesProduct);
}

class DiscountVisitor implements Visitor{
    private double discountPrice;
    @Override
    public void visit(DigitalProduct digitalProduct) {
        discountPrice = digitalProduct.getPrice() * 0.7;
        System.out.println("数码产品打七折," + digitalProduct.getName() + "的价格为:" + discountPrice);
    }
    @Override
    public void visit(ClothesProduct clothesProduct) {
        discountPrice = clothesProduct.getPrice() * 0.8;
        System.out.println("衣物打八折," + clothesProduct.getName() + "的价格为:" + discountPrice);
    }
}

class PurchaseVisitor implements Visitor{
    @Override
    public void visit(DigitalProduct digitalProduct) {
        System.out.println("购买的商品" + digitalProduct.getName() + "需要付款:" + digitalProduct.getPrice() + "元");
    }
    @Override
    public void visit(ClothesProduct clothesProduct) {
        System.out.println("购买的商品" + clothesProduct.getName() + "需要付款:" + clothesProduct.getPrice() + "元");
    }
}

public class VisitorPattern {
    public static void main(String[] args) {
        ClothesProduct clothesProduct = new ClothesProduct("阿迪外套", 500);
        DigitalProduct digitalProduct = new DigitalProduct("手机", 4000);
        DiscountVisitor discountVisitor = new DiscountVisitor();
        PurchaseVisitor purchaseVisitor = new PurchaseVisitor();
        purchaseVisitor.visit(clothesProduct);
        discountVisitor.visit(clothesProduct);
        purchaseVisitor.visit(digitalProduct);
        discountVisitor.visit(digitalProduct);
    }
}
  • 7
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Wistain

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值