二十三种设计模式

二十三种设计模式

1.创建型设计模式

​ 提供实例化的方法,为适合的状态提供相应的对象创建方法

*单例(Singleton)

​ 某个类只生成一个实例,该类提供一个全局访问点来供外部获取该实例,拓展->有限多例模式。

​ **饿汉式:**线程安全,调用效率高,但是不能延时加载。

public class SingletonDemo1 {
    private static SingletonDemo1 instance = new SingletonDemo1();
  
    private SingletonDemo1(){
    }
  
    public static SingletonDemo1 getInstance(){
        return instance;
    }
}

​ **懒汉式:**线程安全,调用效率不高,但是能延时加载。

public class SingletonDemo2 {
    //类初始化时,不初始化这个对象(延时加载,真正用的时候再创建)
    private static SingletonDemo2 instance;

    //构造器私有化
    private SingletonDemo2(){
    }
  
    //方法同步,调用效率低
    public static synchronized SingletonDemo2 getInstance(){
        if(instance==null){
            instance=new SingletonDemo2();
        }
        return instance;
    }
}

​ **双重校验:**懒汉式直接在方法上加锁,当遇到多线程同时调用时,必须排队。所以双重校验不在方法上加锁,只有前n个线程同时调用时会进行排队,但是当第一个调用成功,对象成功创建之后,后面的再次调用就会直接返回实例对象。

public class SingletonDemo3 {
    private volatile static SingletonDemo3 singletonDemo3;

    private SingletonDemo3() {
    }

    public static SingletonDemo3 newInstance() {
      	// 第一次校验
        if (singletonDemo3 == null) {
          	// 加锁
            synchronized (SingletonDemo3.class) {
              	// 第二次校验
                if (singletonDemo3 == null) {
                    singletonDemo3 = new SingletonDemo3();
                }
            }
        }
        return singletonDemo3;
    }
}

​ **静态内部类:**线程安全,调用效率高,可以延时加载。

public class SingletonDemo4 {
    /** 静态内部类 */
    private static class SingletonClassInstance {
        private static final SingletonDemo4 instance = new SingletonDemo4();
    }

    private SingletonDemo4(){}

    public static SingletonDemo4 getInstance(){
        return SingletonClassInstance.instance;
    }
}

​ **枚举类:**枚举类本身就是单例。

原型(Prototype)

​ 将一个对象作为原型,对其进行克隆出多个和原型类似的新实例。构造函数不会执行。

​ 使用场景:类的初始化需要耗费非常多的资源;通过new产生一个对象需要非常繁琐的数据准备或访问;一个对象需要提供给其他对方访问,而且每个调用者可能都需要修改其值时。

​ 浅拷贝:会共享容器(集合等)类型(操作新对象,原对象也会发生变化),使得克隆后得到的新对象不是自己想要的对象。

​ 深拷贝:通过重写clone方法,重新实例化对象中的容器属性,让它变成一个空集合。

@Override
    protected Prototype1 clone() {
        Prototype1 prototype1 = null;
        try {
            prototype1 = (Prototype1)super.clone();
            prototype1.setArrayList(new ArrayList<>());
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
        }
        return prototype1;
    }

*工厂方法(FactoryMethod)

定义一个创建产品族的接口,由子类决定去生产什么产品。

**简单工厂:**简单工厂其实不是一个设计模式,反而比较像是一种编程习惯。

/**
	* 简单工厂
	*/
public class SimplePizzaFactory {
    public Pizza createPizza(String pizzaType) {
        Pizza pizza = null;
        if (pizzaType.equals("cheese")) {
            pizza = new CheesePizza();
        } else if (pizzaType.equals("pepperoni")) {
            pizza = new PepperoniPizza();
        } else if (pizzaType.equals("clam")) {
            pizza = new ClamPizza();
        } else if (pizzaType.equals("veggie")) {
            pizza = new VeggiePizza();
        }
        return pizza;
    }
}

public class PizzaStoreV1 {
    private SimplePizzaFactory factory;

    public PizzaStoreV1(SimplePizzaFactory factory) {
        this.factory = factory;
    }

    public Pizza orderPizza(String pizzaType) {
        Pizza pizza = factory.createPizza(pizzaType);
        pizza.prepare();
        pizza.bake();
        pizza.cut();
        pizza.box();
        return pizza;
    }
}

public class PizzaStoreTest {
    private static void pizzaStoreV1Test() {
        PizzaStoreV1 pizzaStore = new PizzaStoreV1(new SimplePizzaFactory());
        pizzaStore.orderPizza("cheese");
    }
}

​ **工厂方法:**定义了一个创建对象的接口(类或接口中的方法),但由子类决定要实例化哪一个。工厂方法实例化推迟到子类。

**意图:**工厂模式包含一个超类。这个超类提供一个抽象化的接口来创建一个特定类型的对象,而不是决定哪个对象可以被创建。

适用性:

  1. 当一个类不知道他所必须创建的对象的类的时候。
  2. 当一个类希望由它的子类来指定他所创建的对象的时候。
  3. 当类将创建对象的职责委托给多个帮助子类种的某一个,并且你希望将那一个帮助子类是代理者这一信息局部化的时候。
  4. 当需要创建的对象不多且不会频繁增加的时候。

举例:

  1. 多种数据库的实例。
  2. 多种格式文件解析器。
  3. 根据不同环境加载配置文件。
/**
* 披萨店抽象方法
*/
public abstract class PizzaStoreV2 {
    protected abstract Pizza createPizza(String pizzaType);
    public Pizza orderPizza(String pizzaType) {
        Pizza pizza = createPizza(pizzaType);
        pizza.prepare();
        pizza.bake();
        pizza.cut();
        pizza.box();
        return pizza;
    }
}

/**
* 继承并实现方法(子类决定要实例化哪一个)
*/
public class NYPizzaStore extends PizzaStoreV2 {
    protected Pizza createPizza(String pizzaType) {
        Pizza pizza = null;
        if (pizzaType.equals("cheese")) {
            pizza = new NYCheesePizza();
        } else if (pizzaType.equals("pepperoni")) {
            pizza = new NYPepperoniPizza();
        } else if (pizzaType.equals("clam")) {
            pizza = new NYClamPizza();
        } else if (pizzaType.equals("veggie")) {
            pizza = new NYVeggiePizza();
        }
        return pizza;
    }
}

public class PizzaStoreTest {
    private static void pizzaStoreV1Test() {
      	// 选择纽约地区的披萨店
        PizzaStoreV2 pizzaStore = new NYPizzaStore(); 
        pizzaStore.orderPizza("cheese");
    }
}

*抽象工厂模式(Abstract Factory):

​ 定义:提供一个接口,用于创建相关或依赖对象的家族,而不需要明确指定具体类

​ 工厂方法:通过抽象方法提供对象生成入口。

​ 抽象工厂:通过接口,来创建一组产品。

抽象工厂模式与工厂方法模式的最大区别就在于,工厂方法模式针对的是一个产品等级结构;而抽象工厂模式则需要面对多个产品等级结构。

/**
 * 原料抽象工厂,每一种原料有多种实现
 **/
public interface PizzaIngredientFactory {
    Dough createDough();
    Sauce createSauce();
    Cheese createCheese();
    Clams createClams();
}

/**
 *  纽约原料工厂(根据地区选择不同实现的原料)
 **/
public class NYPizzaingredientFactory implements PizzaIngredientFactory {
    public Dough createDough() {
        return new ThickCrustDough();
    }

    public Sauce createSauce() {
        return new PlumTomatoSauce();
    }
  
    public Cheese createCheese() {
        return new MozzarellaCheese();
    }
  
    public Clams createClams() {
        return new FrozenClams();
    }
}

/**
	* 披萨(原材料自定义)
	*/
public abstract class Pizza {
    protected String name;
    protected Dough dough;
    protected Sauce sauce;
    protected Cheese cheese;
    protected Clams clams;
    protected PizzaIngredientFactory pizzaIngredientFactory;

    /** 准备原材料 */
    public abstract void prepare();

    public void bake() {
        System.out.println("pizzaIngredientFactory bake()");
    }
    public void cut() {
        System.out.println("pizzaIngredientFactory cut()");
    }
    public void box() {
        System.out.println("pizzaIngredientFactory box()");
    }
}


/**
	* 不同口味披萨实现
	*/
public class CheesePizza extends Pizza {
    public CheesePizza(PizzaIngredientFactory pizzaIngredientFactory) {
        this.pizzaIngredientFactory = pizzaIngredientFactory;
    }

    public void prepare() {
      	// 根据传入的原料工厂,获取原料
        System.out.println("CheesePizza prepare()");
        dough = pizzaIngredientFactory.createDough();
        sauce = pizzaIngredientFactory.createSauce();
        cheese = pizzaIngredientFactory.createCheese();
    }
}

public abstract class PizzaStoreV3 {
    protected abstract Pizza createPizza(String pizzaType);
    public Pizza orderPizza(String pizzaType) {
        Pizza pizza = createPizza(pizzaType);
        pizza.prepare();
        pizza.bake();
        pizza.cut();
        pizza.box();
        return pizza;
    }
}

public class NYPizzaStore extends PizzaStoreV3 {
    protected Pizza createPizza(String pizzaType) {
        Pizza pizza = null;
        // 实例化纽约的原料工厂
        PizzaIngredientFactory pizzaIngredientFactory = new NYPizzaingredientFactory();
        if (pizzaType.equals("cheese")) {
          	// 创建奶酪披萨
            pizza = new CheesePizza(pizzaIngredientFactory);
        } else if (pizzaType.equals("pepperoni")) {
            pizza = new PepperoniPizza(pizzaIngredientFactory);
        } else if (pizzaType.equals("clam")) {
            pizza = new ClamPizza(pizzaIngredientFactory);
        } else if (pizzaType.equals("veggie")) {
            pizza = new VeggiePizza(pizzaIngredientFactory);
        }
        return pizza;
    }
}

public class PizzaStoreTest {
    private static void pizzaStoreV1Test() {
        PizzaStoreV3 pizzaStore = new NYPizzaStore();
        pizzaStore.orderPizza("cheese");
    }
}

建造者/生成器模式(Builder)

​ 将一个复杂对象分解成多个相对简单的部分,然后根据不同需要分别创建它们,最后构建成该复杂对象。

​ 定义:使用生成器模式,可以封装一个产品的构造过程,并允许按步骤构造产品。

​ 优点:将一个复杂对象的创建过程封装起来;允许对象通过过个步骤来撞见,并且可以改变过程,产品的实现可以被替换,因为客户只看到一个抽象接口。

​ 用途和缺点:经常被用来创建组合结构;与工厂模式相比,采用生成器模式创建对象的客户,需要具备更多领域的知识。

public class Car {
    private String engine = "普通标准的发动机";
    private String gear = "普通标准的齿轮";
    private String door = "普通标准的车门";
    private String wheel = "普通标准的轮胎";
}

public interface Builder {
    // 安装引擎
    Builder initalEngine(String engine);
    // 安装齿轮
    Builder initalGear(String gear);
    // 安装车门
    Builder initalDoor(String door);
    // 安装轮胎
    Builder initailWheel(String wheel);
    // 获得构建后的汽车
    Car getCar();
}

public class AudiBuilder implements Builder {
    private Car car;
  
    public AudiBuilder() {
        car = new Car("Audi普通的发动机",
                "Audi普通标准的齿轮",
                "Audi普通标准的车门",
                "Audi普通标准的轮胎");
    }

    @Override
    public Builder initalEngine(String engine) {
        car.setEngine(engine);
        return this;
    }

    @Override
    public Builder initalGear(String gear) {
        car.setGear(gear);
        return this;
    }

    @Override
    public Builder initalDoor(String door) {
        car.setDoor(door);
        return this;
    }

    @Override
    public Builder initailWheel(String wheel) {
        car.setWheel(wheel);
        return this;
    }

    @Override
    public Car getCar() {
        return car;
    }
}

// 安装汽车的工人
public class Worker {
    Car createA4LCar() {
        return new AudiBuilder().initalEngine("Audi的4缸发动机").initalGear("6速双离合变速箱").initalDoor("A4L的门").getCar();
    }

    Car createR8Car() {
        return new AudiBuilder().
                initalEngine("16缸跑车引擎").
                initalDoor("碳纤维轻量级车门").
                initalGear("7档湿式双离合变速箱").
                initailWheel("米其林Top2竞速级轮胎").
                getCar();
    }

    Car createCommonBMW() {
        return new BMWBuilder().getCar();
    }
}

public class BuilderTest {
    public static void main(String[] args) {
        Worker worker = new Worker();
        Car audiR8 = worker.createR8Car();
        Car audiA4L = worker.createA4LCar();
        Car commonBMW = worker.createCommonBMW();

        System.out.println("audiR8=" + audiR8);
        System.out.println("audiA4L=" + audiA4L);
        System.out.println("commonBMW=" + commonBMW);
    }
}

2.结构型设计模式

描述如何将类或者对象按某种布局组成更大的结构,分为类结构型模式(采用继承机制来组合接口和类)和对象结构型模式(采用组合或聚合来组合对象)

通常用来处理实体之间的关系,使得这些实体能够更好的协同工作。

*代理(Proxy)

​ 解决问题:想要对一个业务类进行某些横切性的增强时

​ 定义:代理模式为另一个对象提供一个替身或占位符,以控制对这个对象的访问。使用代理模式创建对象,让代理对象控制某对象的访问,被代理的对象可以是远程的对象、创建开销大的对象或需要安全控制的对象。

​ 实例:SpringAOP中采用JDK动态代理。

public interface Subject {
    void request();
}

public class RealSubject implements Subject {
    @Override
    public void request() {
        System.out.println("-----RealSubject 开始执行业务操作-----");
    }
}

// 代理类
public class Proxy implements Subject {
    // 被代理的对象
    private Subject subject;

    public Proxy(Subject subject) {
        this.subject = subject;
    }

    @Override
    public void request() {
        beforeProcessor();
        subject.request();
        afterProcessor();
    }

    private void beforeProcessor() {
        System.out.println("-----Proxy before processor-----");
    }

    private void afterProcessor() {
        System.out.println("-----Proxy after processor-----");
    }
}

public class ProxyTest {
    public static void main(String[] args) {
        // Subject subject = new RealSubject();
        Subject subject = new Proxy(new RealSubject());
        subject.request();
    }
}

*适配器(Adapter)

​ 定义:将一个类的接口,转换成客户期望的另一个接口。适配器让原本不兼容的类可以合作无间。

public interface Target {
    void prepare();
    void execute();
}

// 正常的符合Target接入标准的类
public class NormalTarget implements Target {
    public void prepare() {
        System.out.println("NormalTarget prepare()");
    }

    public void execute() {
        System.out.println("NormalTarget execute()");
    }
}

// 待适配的类,无法正常的符合Target接入标准的类
public class Adaptee {
    public void prepare1() {
        System.out.println("Adaptee prepare1()");
    }
    public void prepare2() {
        System.out.println("Adaptee prepare2()");
    }
    public void prepare3() {
        System.out.println("Adaptee prepare3()");
    }
    public void doingSomething() {
        System.out.println("Adaptee doingSomething()");
    }
}

// 适配器
public class Adapter implements Target {
    // 待适配的类
    private Adaptee adaptee;

    public Adapter(Adaptee adaptee) {
        this.adaptee = adaptee;
    }

    public void prepare() {
        adaptee.prepare1();
        adaptee.prepare2();
        adaptee.prepare3();
    }

    public void execute() {
        adaptee.doingSomething();
    }
}

public class Client {
    Target target;

    public void work() {
        target.prepare();
        target.execute();
    }

    public void setTarget(Target target) {
        this.target = target;
    }
}

public class AdapterTest {
    public static void main(String[] args) {
        Client client = new Client();

        System.out.println("------------NormalTarget------------");
        client.setTarget(new NormalTarget());
        client.work();

        System.out.println("------------Adaptee------------");
        client.setTarget(new Adapter(new Adaptee())); // 适配器转换
        client.work();
    }
}

桥接(Bridge)

​ 定义:将抽象部分和实现部分分离解耦,使两者可以独立变化,桥接模式通过将实现和抽象放在两个不同的类层次中使得它们可以独立变化。

​ 优点:将实现予以解耦,抽象和实现可以独立扩展,不会影响到对方;对于“具体的抽象类”所做的改变,不会影响到客户。

​ 用途和缺点:适合使用在需要跨越多个平台的图形和窗口系统上;当需要用不同方式改变接口和实现时,桥接模式很好用;缺点是增加了复杂度。

// 颜色大类
public interface ColorImplementor {
    String getColor();
}

/**
 * 抽象画笔类
 */
@Data
public abstract class BrushPenAbstraction {
    // 颜色接口(Has-A关系,桥接)
    protected ColorImplementor color;
    // 绘画操作
    public abstract void draw();
}

/**
 * 粗毛笔实现类
 */
public class BigBurshPen extends BrushPenAbstraction {
    @Override
    public void draw() {
        System.out.println("Big and " + color.getColor() + " drawing!");
    }
}

/**
 * 桥梁模式测试类
 */
public class BridgeTest {
    public static void main(String[] args) {
      	// BigBurshPen为BrushPenAbstraction的实现类
        BrushPenAbstraction brushPen = new BigBurshPen();
      	// RedColor为ColorImplementor的实现
        brushPen.setColor(new RedColor());
        brushPen.draw();

        brushPen.setColor(new BlueColor());
        brushPen.draw();

        brushPen = new SmallBurshPen();
        brushPen.setColor(new BlueColor());
        brushPen.draw();
    }
}

*装饰(Decorator)

​ 定义:动态的将责任附加到对象上,若要扩展功能,装饰者提供了比继承更有弹性的替代方案。

把每个要装饰的功能放在单独的类中,用这个类去包装所要装饰的对象,因此客户端可以有选择地、按顺序的使用装饰功能包装对象。

// 食物抽象类
public abstract class Food {
    String description = "食物";
    public String getDescription() {
        return description;
    }
    public abstract double cost();
}

// 辅料抽象类
public abstract class AccessoriesDecorator extends Food {
    public abstract String getDescription();
}

// 基础版
public class JianBing extends Food {
    public JianBing() {
        description = "基础版煎饼果子";
    }
    public double cost() {
        System.out.println("基础版煎饼果子售价:" + 7 + "元");
        return 7;
    }
}

// 鸡蛋
public class Egg extends AccessoriesDecorator {
    private Food food;
    public Egg(Food food) {
        this.food = food;
    }
    public String getDescription() {
        return "鸡蛋";
    }
    public double cost() {
        System.out.println("添加鸡蛋售价:" + 1 + "元");
        return 1 + food.cost();
    }
}

// ...其他辅料类

public class DecoratorTest {
    public static void main(String[] args) {
        // 创建煎饼果子
        Food jianBing = new JianBing();
        // 创建鸡蛋,加入到煎饼果子中
        Food egg = new Egg(jianBing);
        // 创建香肠,加入到煎饼果子中
        Food sausage = new Sausage(egg);
        System.out.println("总金额为:" + sausage.cost() + "元");
    }
}

*门面/外观(Facede)

​ 定义:提供一个统一的接口,用来访问子系统中的一群接口。外观定义了一个高层接口,让子系统更容易使用。

使用门面模式的最常见理由是为一个复杂系统提供单个简单的入口点。引入外观之后,客户端代码通过简单地调用一个方法/函数就能使用一个系统。同时内部系统并不会丢失任何功能,外观只是封装了内部系统。

public class Door {
    public void lock() {
        System.out.println("Door lock");
    }
}

// ...其他操作

// 汽车
public class Car {
    private Engine engine;
    private Door door;
    private DashboardDisplay display;
    private Key key;

    public Car() {
        engine = new Engine();
        door = new Door();
        display = new DashboardDisplay();
        key = new Key();
    }

    /** 汽车启动 */
    public void start() {
        if (key.turns()) {
            door.lock();
            engine.start();
            display.refreshDisplay();
        }
    }
}

public class ClientTest {
    public static void main(String[] args) {
        Car car = new Car();
        car.start(); // 启动汽车,用户并不知道引擎、车门、钥匙、中控的运作
    }
}

享元(Flyweight)

​ 定义:享元模式是池技术的重要实现方式,其定义如下:使用共享对象可以有效的支持大量的细粒度的对象。(key:value,value是一个对象)

public class PersonInfo {
    // 姓名
    private String name;
    // 居住的详细地址
    private String address;
    // 核酸医院或网点唯一标识
    private Integer nucleicId;
}

public class NucleicInfo {
    // 唯一标识
    private Integer id;
    // 核酸医院网点名称
    private String name;
}

/**
 * 核酸医院和网点信息客户端类
 */
public class NucleicInfoClient {
    // 存储核酸医院和网点的pool
    private HashMap<Integer, NucleicInfo> pool = Maps.newHashMap();

    // 构造函数中初始化池中数据
    public NucleicInfoClient() {
        NucleicInfo nucleicInfo;
        for (int i = 1; i <=10; i++) {
            nucleicInfo = new NucleicInfo(i, "北京市第"+i+"医院核酸网点");
            pool.put(nucleicInfo.getId(), nucleicInfo);
        }
    }

    public NucleicInfo getNucleicInfo(Integer key) {
        if (key == null || !pool.containsKey(key)) {
            return null;
        }
        return pool.get(key);
    }
}

/**
 * 蝇量模式测试类
 */
public class FlyweightTest {
    private static NucleicInfoClient client = new NucleicInfoClient();
  
    public static void main(String[] args) {
        PersonInfo bob = new PersonInfo("bob", "北京市海淀区xx大街xx小区x号楼x号", 2);
        PersonInfo muse = new PersonInfo("muse", "北京市朝阳区yy大街yy小区y号楼y号", 7);
        PersonInfo john = new PersonInfo("john", "上海市市徐汇区zz大街zz小区z号楼z号", 4);

        printPersonInfo(bob);
        printPersonInfo(muse);
        printPersonInfo(john);
    }

    public static void printPersonInfo(PersonInfo personInfo) {
        NucleicInfo nucleicInfo = client.getNucleicInfo(personInfo.getNucleicId());
        System.out.println(String.format("姓名=%s 居住地址=%s 核酸网点=%s", personInfo.getName(), personInfo.getAddress(),
                nucleicInfo.getName()));
    }
}

组合(Composite)

​ 定义:允许将对象组合成树形结构来表现“整体/部分”层次接口。组合能让客户以一致的方式处理个别对象以及对象集合(树形结构)。

可以理解为公司的架构模式。

/**
 * 职员类
 */
@AllArgsConstructor
public abstract class AbstractCorp {
    // 职员姓名
    private String name = "";
    // 职员的职位
    private String position = "";
    // 职员的薪水
    private int salary = 0;
    // 获得职员信息
    public String getCorpInfo() {
        return String.format("姓名:%s 职位:%s 薪水:%d", name, position, salary);
    }
}

/**
 * 管理层员工(即:非叶子节点职员)
 */
public class BranchCorp extends AbstractCorp {
    private ArrayList<AbstractCorp> corps = Lists.newArrayList();
    public BranchCorp(String name, String position, int salary) {
        super(name, position, salary);
    }
    // 添加职员
    public void addSubCorp(AbstractCorp... corp) {
        corps.addAll(Arrays.asList(corp));
    }
    // 返回手下的职员
    public ArrayList<AbstractCorp> getSubCorp() {
        return corps;
    }
}

/**
 * 基层员工(即:叶子节点职员)
 */
public class LeafCorp extends AbstractCorp {
    public LeafCorp(String name, String position, int salary) {
        super(name, position, salary);
    }
}

public class CompositeTest {
    public static void main(String[] args) {
        // 创建公司所有职员
        BranchCorp a = new BranchCorp("A", "董事长", 100000);
        BranchCorp b = new BranchCorp("B", "技术总监", 70000);
        BranchCorp c = new BranchCorp("C", "人事总监", 60000);
        BranchCorp d = new BranchCorp("D", "财务总监", 50000);
        LeafCorp b1 = new LeafCorp("B1", "程序员", 30000);
        LeafCorp b2 = new LeafCorp("B2", "程序员", 20000);
        LeafCorp c1 = new LeafCorp("C1", "HR", 15000);
        LeafCorp d1 = new LeafCorp("D1", "会计", 13000);

        // 根据下属关系,构建树形结构
        a.addSubCorp(b, c, d);
        b.addSubCorp(b1, b2);
        c.addSubCorp(c1);
        d.addSubCorp(d1);

        // 获得下属信息
        System.out.println("-----a的下属-----");
        getSubCorp(a);
        System.out.println("-----b的下属-----");
        getSubCorp(b);
    }

    // 获得branchCorp的下属
    private static void getSubCorp(BranchCorp branchCorp) {
        for (AbstractCorp corp : branchCorp.getSubCorp()) {
            System.out.println("corp = " + corp.getCorpInfo());
            if (corp instanceof BranchCorp) {
                getSubCorp((BranchCorp) corp);
            }
        }
    }
}

3.行为型设计模式

定义:行为型模式用于描述程序在运行时复杂的流程控制,即:描述多个类和对象之间怎样相互协作共同完成单个对象都无法单独完成的任务,它涉及算法与对象间职责的分配。

行为型模式分为类行为模式(采用继承机制来在类间分派行为)和对象行为模式(采用组合或者聚合在对象间分派行为)。由于组合关系或者聚合关系比继承关系耦合度低,满足“合成复用原则”,所以对象行为模式比类行为模式具有更大灵活性。

用于在不同实体间进行通信,为实体之间的通信提供更容易更灵活的通信方法。

*模版方法(TemplateMethod)

​ 定义:在一个方法中定义一个算法骨架,而将一些步骤延迟到子类中。模版方法使得子类可以在不改变算法结构的情况下重新定义算法中的某些步骤。

模版方法模式由一个抽象类和一个(一组)实现类通过继承结构组成。抽象类中的方法分为三种:

  1. 抽象方法:父类只声明不实现,定义好规范,由子类实现。
  2. 模版方法:抽象类声明并实现。一般来说,模版方法调用抽象方法来完成主要逻辑功能,并且模版方法大多会定义为final类型,指明主要的逻辑功能在子类中不能被重写。
  3. 钩子方法:由抽象类声明并实现,但是子类可以去扩展,子类可以通过扩展扣子方法来影响模版方法的逻辑。
//饮品制作类
public abstract class MakeBeverage {
    // 准备食谱(防止子类覆盖这个方法)
    final void prepareRecipe() {
        /** 第一步:把水煮沸 */
        boilWater();
        /** 第二步:酿造饮品 */
        brew();
        /** 第三步:把饮品倒入杯子中 */
        pourInCup();
        /** 第四步:往饮品中增加调味品 */
        addCondiments();
    }

    // 酿造
    abstract void brew();

    // 往饮品中增加调味品
    abstract void addCondiments();

  	// 公共方法
    protected void boilWater() {
        System.out.println("把水煮沸");
    }
  	// 公共方法
    private void pourInCup() {
        System.out.println("把饮品倒入杯子中");
    }
}

// 冲泡茶叶,可更换为咖啡,实现不一样
public class Tea extends MakeBeverage {
    @Override
    protected void brew() {
        System.out.println("用沸水浸泡茶叶");
    }

    @Override
    protected void addCondiments() {
        System.out.println("往茶叶中添加柠檬");
    }
}

public class TemplateTest {
    public static void main(String[] args) {
        System.out.println("-----------开始冲泡茶叶-----------");
        Tea tea = new Tea();
        tea.prepareRecipe();
    }
}

*策略(Strategy)

​ 定义:定义了算法族,分别封装起来,让他们之间可以互相替换,此模式让算法的变化独立于使用算法的用户。

策略模式的结构

  • **封装类:**也叫上下文,对策略进行二次封装,目的是避免高层模块对策略的直接调用。
  • **抽象策略:**通常情况下为一个接口,当各个实现类中存在着重复的逻辑时,则使用抽象类来封装这部分公共的代码,此时,策略模式看上去更像是模版方法模式。
  • **具体策略:**具体策略角色通常由一组封装了算法的类来担任,这些类之间可以根据需要自由替换。
// 定义算法族,如:飞行、叫声
// 飞行行为
public interface FlyBehavior {
    void fly();
}

// 飞行,也可以实现为不会飞行
public class FlyWithWings implements FlyBehavior {
    public void fly() {
        System.out.println("实现鸭子的飞行");
    }
}

// 鸭子抽象类
public abstract class Duck {
  	// 算法族(多个) 
    protected FlyBehavior flyBehavior;
  	// 其他特殊实现
    public abstract void display();
    public void swin() {
        System.out.println("鸭子游泳");
    }
   	
    public void performFly() {
        flyBehavior.fly();
    }
    public void setFlyBehavior(FlyBehavior flyBehavior) {
        this.flyBehavior = flyBehavior;
    }
}

public class RubberDuck extends Duck {
    public RubberDuck() {
        flyBehavior = new FlyNoWay(); // 不会飞
        quackBehaviorBehavior = new Squeak(); // 橡皮鸭的吱吱叫
    }
    public void display() {
        System.out.println("橡皮鸭的外貌特征");
    }
}

public class StrategyTest {
    public static void main(String[] args) {
        // 生成橡皮鸭
        Duck rubberDuck = new RubberDuck();
        rubberDuck.display();
        rubberDuck.performFly();
        System.out.println("-----------对橡皮鸭进行改造,让它能飞起来------------");
        rubberDuck.setFlyBehavior(new FlyWithWings()); // 更换会飞的算法族
        rubberDuck.performFly();
    }
}

命令(command)

​ 定义:将“请求”封装成命令对象,以便使用不同的请求、队列或日志来参数化其他对象。

命令模式的结构:

  • **Command类:**是一个抽象类,类中对需要执行的命令进行声明,一般来说要对外公布一个execute方法用来执行命令。
  • **ConcreteCommand类:**Command类的实现类,对抽象类中声明的方法进行实现。
  • **Client类:**最终的客户端调用类。

以上三个类的作用应该是比较好理解的,下面我们重点说一下Invoker类和Recevier类。

  • **Invoker类:**调用者,负责调用命令。
  • **Receiver类:**接收者,负责接收命令并且执行命令。
public interface Command {
    void execute();
}

public class Light {
    /** 开灯操作 */
    public void on() {
        System.out.println("Light on!");
    }
    /** 关灯操作 */
    public void off() {
        System.out.println("Light off!");
    }
}

// 关灯命令实现
public class LightOffCommand implements Command {
    private Light light;
    public LightOffCommand(Light light) {
        this.light = light;
    }
    public void execute() {
        light.off();
    }
}

// 遥控器
public class RemoteController {
    private Command[] onCommands;
    private Command[] offCommands;

    public RemoteController() {
        onCommands = new Command[8];
        offCommands = new Command[8];

        for (int i = 0; i < 8; i++) {
            onCommands[i] = new NoCommand();
            offCommands[i] = new NoCommand();
        }
    }

    /** 往遥控器中添加命令 */
    public void addCommand(int slot, Command onCommand, Command offCommand) {
        onCommands[slot] = onCommand;
        offCommands[slot] = offCommand;
    }

    /** 按遥控器中某个开启键 */
    public void pushOnButton(int slot) {
        onCommands[slot].execute();
    }

    /** 按遥控器中某个关闭键 */
    public void pushOffButton(int slot) {
        offCommands[slot].execute();
    }
}

public class CommandTest {
    public static void main(String[] args) {
        Light light = new Light();
        RemoteController controller = new RemoteController();
      	// 添加命令
        controller.addCommand(0, new LightOnCommand(light), new LightOffCommand(light));
        // 按下遥控器,第一排的ON按钮
        controller.pushOnButton(0);
        // 按下遥控器,第一排的OFF按钮
        controller.pushOffButton(0);
    }
}

职责链(Chain Of Respomsibility)

​ 定义:当想让一个以上对象有机会能够处理某个请求的时候,就使用责任链模式。使多个对象都有机会处理请求,从而避免了请求的发送者和接受者之间的耦合关系。将这些对象连成一条链,并沿着这条链传递该请求,直到有对象处理它为止。

责任连模式的结构

责任连模式的类图非常简单,它由一个抽象地处理类和它的一组实现类组成:

  • **抽象处理类:**抽象处理类中主要包含一个指向下一处理类的成员变量nextHandler和一个处理请求的方法handRequest,handRequest方法的主要主要思想是,如果满足处理的条件,则有本处理类来进行处理,否则由nextHandler来处理。
  • **具体处理类:**具体处理类主要是对具体的处理逻辑和处理的适用条件进行实现。
/**
 * 抽象处理类
 */
public abstract class AbstractProcessor {
    // 责任链中下一个处理节点
    private AbstractProcessor nextProcessor;
    // 返回的处理结果
    private String result;
    public final String handleMessage(List<Email> emails) {
        List<Email> filterEmails =
                emails.stream().filter(email -> email.getType() == this.emailType()).collect(Collectors.toList());
        result = this.execute(filterEmails);
        if (this.nextProcessor == null) {
            return result;
        }
        return this.nextProcessor.handleMessage(emails);
    }

    // 设置责任链的下一个处理器
    public void setNextProcessor(AbstractProcessor processor) {
        this.nextProcessor = processor;
    }

    // 获得当前Processor可以处理的邮件类型
    protected abstract int emailType();

    // 具体处理方法
    protected abstract String execute(List<Email> emails);
}

/**
 * 法律部门/CEO/垃圾邮件/业务部门处理类
 */
public class LawProcessor extends AbstractProcessor {
    @Override
    protected int emailType() {
        return EmailType.SLANDER_EMAIL.type;
    }

    @Override
    protected String execute(List<Email> emails) {
        if (CollectionUtils.isNotEmpty(emails)) {
            System.out.println("-------法律部门开始处理邮件-------");
            emails.stream().forEach(email -> System.out.println(email.getContent()));
        }
        return "任务执行完毕!";
    }
}

/**
 * 责任链模式测试类
 */
public class ChainTest {
    // 初始化待处理邮件
    private static List<Email> emails = Lists.newArrayList(new Email(EmailType.FANS_EMAIL.type, "我是粉丝A"),
            new Email(EmailType.COOPERATE_EMAIL.type, "我要找你们合作"),
            new Email(EmailType.GARBAGE_EMAIL.type, "我是垃圾邮件"),
            new Email(EmailType.FANS_EMAIL.type, "我是粉丝B"));

    public static void main(String[] args) {
        // 初始化处理类
        AbstractProcessor ceoProcessor = new CeoProcessor();
        AbstractProcessor lawProcessor = new LawProcessor();
        AbstractProcessor businessProcessor = new BusinessProcessor();
        AbstractProcessor garbageProcessor = new GarbageProcessor();

        // 设置责任链条
        ceoProcessor.setNextProcessor(lawProcessor);
        lawProcessor.setNextProcessor(businessProcessor);
        businessProcessor.setNextProcessor(garbageProcessor);

        // 开始处理邮件
        ceoProcessor.handleMessage(emails);
    }
}

状态(State)

​ 定义:允许对象在哪不状态改变时改变它的行为,对象看起来好像修改了它的类。

不同的状态类中实现不同操作后造成的结果,在任何状态进行任何操作后,都会得到合适的反馈。

/**
 * 状态接口类
 */
public interface State {
    // 投入硬币操作
    void insertQuarter();
    // 退出硬币操作
    void ejectQuarter();
    // 扭转曲柄操作
    void turnCrank();
    // 发放糖果操作
    void dispense();
}

/**
 * 糖果售卖机
 */
@Data
public class GumballMachine {
    private State noQuarterState;
    private State hasQuarterState;
    private State soldState;
    private State soldOutState;
    private State state = soldOutState; // 糖果机默认状态为售罄状态
    int count = 0; // 糖果库存量

    public GumballMachine(int numberGumballs) {
        noQuarterState = new NoQuarterState(this);
        hasQuarterState = new HasQuarterState(this);
        soldState = new SoldState(this);
        soldOutState = new SoldOutState(this);
        count = numberGumballs;
        if (numberGumballs > 0) {
            state = noQuarterState; // 如果采购了糖果球(numberGumballs>0),则糖果机的状态为未投币状态
        }
    }

    // 投入钱币
    public void insertQuarter() {
        state.insertQuarter();
    }
    // 退出钱币
    public void ejectQuarter() {
        state.ejectQuarter();
    }
    // 扭转曲柄
    public void turnCrank() {
        state.turnCrank();
        state.dispense();
    }
    // 减少库存
    public void releaseBall() {
        if (count > 0) {
            System.out.println("一个糖果球正在出库");
            --count;
        } else {
            System.out.println("库存不足,一个糖果球无法出库");
        }
    }
    // 设置状态
    void setState(State state) {
        this.state = state;
    }
}

/**
 * 没有投放钱币状态类(其他状态实现类)
 */
public class NoQuarterState implements State {

    private GumballMachine gumballMachine;

    public NoQuarterState(GumballMachine gumballMachine) {
        this.gumballMachine = gumballMachine;
    }

    @Override
    public void insertQuarter() {
        System.out.println("投入钱币成功!");
        gumballMachine.setState(gumballMachine.getHasQuarterState()); // 状态流转
    }

    @Override
    public void ejectQuarter() {
        System.out.println("你还没有投入钱币,不能退回钱币!");
    }

    @Override
    public void turnCrank() {
        System.out.println("你还没有投入钱币,不能扭转曲柄!");
    }

    @Override
    public void dispense() {
        System.out.println("你还没有投入钱币,糖果不可以发放!");
    }
}

/**
 * 状态模式测试类
 */
public class StateTest {
    public static void main(String[] args) {
        System.out.println("-----向糖果机中放入1枚糖果-----");
        GumballMachine machine = new GumballMachine(1);

        System.out.println("-----第一次购买糖果-----");
        machine.insertQuarter();
        machine.ejectQuarter();
        machine.turnCrank();

        System.out.println("-----第二次购买糖果-----");
        machine.insertQuarter();
        machine.turnCrank();

        System.out.println("-----第三次购买糖果-----");
        machine.insertQuarter();
        machine.turnCrank();
        machine.ejectQuarter();
    }
}

*观察者(Observer)

​ 定义:定义了对象之间的一对多依赖,这样以来,当一个对象改变状态时,它的所有依赖着都会收到通知并自动更新。

观察者模式的结构

  • **被观察者:**这个角色可以是接口,也可以是抽象类或者具体的类,因为很多情况下会与其他的模式混用,所以使用抽象类的情况比较多。
  • **观察者:**观察者角色一般是一个接口,它只有一个update方法,在被观察者状态发生变化时,这个方法就会被触发调用。
  • **具体的被观察者:**使用这个角色是为了便于扩展,可以在此角色中定义具体的业务逻辑。
  • **具体的观察者:**观察者接口的具体实现,在这个角色中,将定义被观察者对象状态发生变化时所要处理的逻辑。
// 主题接口
public interface Subject {
    void registerObserver(Observer observer);
    void removeObserver(Observer observer);
    void notifyObserver();
}

// 监听者接口
public interface Observer {
    void update();
}

// 实现主题
public class ConcreteSubject implements Subject {
    private List<Observer> observers;
    public ConcreteSubject() {
        this.observers = new ArrayList<>();
    }
    public void registerObserver(Observer observer) {
        observers.add(observer);
    }
    public void removeObserver(Observer observer) {
        observers.remove(observer);
    }
    public void notifyObserver() {
        observers.forEach(observer -> observer.update());
    }
}

// 观察者1
public class ConcreteObserver1 implements Observer {
    public void update() {
        System.out.println("ConcreteObserver1");
    }
}

public class OberverTest {
    public static void main(String[] args) {
        Observer cObserver1 = new ConcreteObserver1();
        Observer cObserver2 = new ConcreteObserver2();
        Observer cObserver3 = new ConcreteObserver3();
        /** 创建主题 */
        ConcreteSubject subject = new ConcreteSubject();

        /** 注册三个监听者*/
        subject.registerObserver(cObserver1);
        subject.registerObserver(cObserver2);
        subject.registerObserver(cObserver3);

        /** 发送通知 */
        System.out.println("----------给cObserver1、cObserver2、cObserver3发通知----------");
        subject.notifyObserver();

        /** 移除一个监听者ConcreteObserver2*/
        subject.removeObserver(cObserver2);
        System.out.println("----------给cObserver1、cObserver3发通知----------");
        subject.notifyObserver();
    }
}

中介者(Mediator)

定义:使用中介者模式来集中相关对象之间复杂的沟通和控制方式。

各自功能类只需要实现自己的功能,各自功能之间交互的所有的业务逻辑都在中介者中实现。

中介者模式的结构

中介者模式又称为调停者模式,共分为3部分:

  • 抽象中介者:定义好同事类对象到中介者对象的接口,用于各个同事类之间的通信。一般包括一个或几个抽象的事件方法,并由子类去实现。
  • 中介者实现类:从抽象中介者继承而来,实现抽象中介者中定义的事件方法。从一个同事类接收消息,然后通过消息影响其他同时类。
  • 同事类:如果一个对象会影响其他的对象,同时也会被其他对象影响,那么这两个对象称为同事类。在类图中,同事类只有一个,这其实是现实的省略,在实际应用中,同事类一般由多个组成,他们之间相互影响,相互依赖。同事类越多,关系越复杂。并且,同事类也可以表现为继承了同一个抽象类的一组实现组成。在中介者模式中,同事类之间必须通过中介者才能进行消息传递。
// 同事抽象类
public abstract class AbstractColleague {
    protected Mediator mediator;
    public AbstractColleague(Mediator mediator) {
        this.mediator = mediator;
    }
}

/**
 * 采购功能
 */
public class Purchase extends AbstractColleague {
    public Purchase(Mediator mediator) {
        super(mediator);
    }
    /** 采购电脑 */
    public void buyComputer(int num) {
        System.out.println();
        super.mediator.purchaseByComputer(num);
    }
    /** 不再采购电脑 */
    public void refuseBuyComputer() {
        System.out.println("不再采购电脑!");
    }
}

/**
 * 库存功能
 */
public class Stock extends AbstractColleague {
    private static int COMPUTER_NUM = 100;

    public Stock(Mediator mediator) {
        super(mediator);
    }

    /** 增加库存 */
    public void increaseComputer(int number) {
        COMPUTER_NUM += number;
        System.out.println("电脑的库存数量为:" + COMPUTER_NUM);
    }

    /** 减少库存 */
    public void decreaseComputer(int number) {
        COMPUTER_NUM -= number;
        System.out.println("电脑的库存数量为:" + COMPUTER_NUM);
    }

    /** 获得当前库存 */
    public int getStockNumber() {
        return COMPUTER_NUM;
    }

    /** 清理库存 */
    public void clearStock() {
        System.out.println("清理库存数量为:" + COMPUTER_NUM);
        super.mediator.stockClear();
    }
}

/**
 * 中介者/调停者
 */
public class Mediator {
    protected Purchase purchase;
    protected Sale sale;
    protected Stock stock;

    public Mediator() {
        purchase = new Purchase(this);
        sale = new Sale(this);
        stock = new Stock(this);
    }

    /** 采购电脑 */
    public void purchaseByComputer(int num) {
        int saleStatus = sale.getSaleStatus();
        // 如果销售情况不好(即:没有超过80台),则采购总数减半
        String msg = "";
        if (saleStatus <= 80) {
            num = num / 2;
            msg = "由于销售不佳,采购总数减半,";
        }
        System.out.println(msg + "原有库存电脑" + stock.getStockNumber() + "台,现采购电脑" + num + "台");
        stock.increaseComputer(num);
    }

    /** 销售电脑 */
    public void saleSellComputer(int num) {
        // 如果库存数量不足,则采购2倍的num电脑数,暂时只售卖库存中有的数量
        int stockNum;
        if ((stockNum = stock.getStockNumber()) < num) {
            purchase.buyComputer(2*num);
            num = stockNum;
        }
        stock.decreaseComputer(num);
    }

    /** 折价销售电脑 */
    public void saleOffSale() {
        System.out.println("折价销售电脑");
    }

    /** 清理库存 */
    public void stockClear() {
        sale.offSale(); // 折价销售电脑
        purchase.refuseBuyComputer(); // 不要采购电脑
    }
}

迭代器(Iterator)

定义:提供一个方法顺序访问一个聚合对象中的各个元素,而又不暴露其内部的表示。

迭代器模式的结构

  • 抽象容器:一般是一个接口,提供一个iterator()方法,例如java中的Collection接口,List接口,Set接口等。
  • 具体容器:就是抽象容器的具体实现类,比如List接口的有序列表实现ArrayList,List接口的链表实现LinkList,Set接口的哈希列表的实现HashSet等。
  • 抽象迭代器:定义遍历元素所需要的方法,一般来说会有这么三个方法:取得第一个元素的方法first(),取得下一个元素的方法next(),判断是否遍历结束的方法isDone()(或者叫hasNext()),移出当前对象的方法remove(),
  • 迭代器实现:实现迭代器接口中定义的方法,完成集合的迭代。
/**
 * 自定义的迭代器
 **/
public interface MenuIterator {
    // 容器中是否还有元素
    boolean hasNext();
    // 获得容器中的下一个元素
    MenuItem next();
}
// 菜单
public interface Menu {
    // 获得迭代器
    MenuIterator iterator();
}

// 菜单项
public class MenuItem {
    // 菜名
    private String name;
    // 菜品详细介绍
    private String desc;
    // 是否是素食
    private boolean vegetarian;
    // 菜的价格
    private double price;

    public MenuItem(String name, String desc, boolean vegetarian, double price) {
        this.name = name;
        this.desc = desc;
        this.vegetarian = vegetarian;
        this.price = price;
    }

    public String getName() {
        return name;
    }

    public String getDesc() {
        return desc;
    }

    public boolean isVegetarian() {
        return vegetarian;
    }

    public double getPrice() {
        return price;
    }
}

// a餐厅实现迭代器(自己遍历的方式),B餐厅可以是数组形式
public class ARestaurantMenuIterator implements MenuIterator {
    private ArrayList<MenuItem> menuItems;
    private Iterator<MenuItem> iterator;
    public ARestaurantMenuIterator(ArrayList<MenuItem> menuItems) {
        this.menuItems = menuItems;
        iterator = menuItems.iterator();
    }
    @Override
    public boolean hasNext() {
        return iterator.hasNext();
    }
    @Override
    public MenuItem next() {
        return iterator.next();
    }
}

// A餐厅菜单
public class ARestaurantMenu implements Menu {
    private ArrayList<MenuItem> menuItems;
    public ARestaurantMenu() {
        menuItems = new ArrayList<>();
        addItem("油条", "油条的描述", true, 0.5);
        addItem("豆浆", "豆浆的描述", true, 1.9);
        addItem("茶叶蛋", "茶叶蛋的描述", true, 1.5);
        addItem("小笼包", "小笼包的描述", true, 2.1);
    }

    private void addItem(String name, String desc, boolean vegetarian, double price) {
        MenuItem menuItem = new MenuItem(name, desc, vegetarian, price);
        menuItems.add(menuItem);
    }

    public ArrayList<MenuItem> getMenuItems() {
        return menuItems;
    }

    @Override
    public MenuIterator iterator() {
        return new ARestaurantMenuIterator(menuItems);
    }
}

public class IteratorTest {
    public static void main(String[] args) {
        /** 构建A餐馆和B餐馆的菜单 */
        ARestaurantMenu aMenu = new ARestaurantMenu();
        BRestaurantMenu bMenu = new BRestaurantMenu();
        /** 构建女服务员 */
        Waitress waitress = new Waitress();
        /** 将A餐馆和B餐馆的菜单传给服务员,让她报出菜单来 */
        waitress.printMenu(aMenu, bMenu);
    }
}

访问者(Visitor)

定义:表示一个作用于对象结构中的各元素的操作。他使你可以在不改变各元素的类的前提下定义作用于这些元素的新操作。

访问者模式包含的角色:

  • **抽象访问者:**抽象类或者接口,声明访问者可以访问哪些元素,具体到程序中就是visit方法中的参数定义哪些对象是可以被访问的。
  • **访问者:**实现抽象访问者所声明的方法,它影响到访问者访问到一个类后该干什么,要做什么事情。
  • **抽象元素类:**接口或者抽象类,声明接受哪一类访问者访问,程序上是通过accept方法中的参数来定义的。抽象元素一般有两类方法,一部分是本身的业务逻辑,另外就是允许接收哪类访问者来访问。
  • **元素类:**实现抽象元素类所声明的accept方法,通常都是visitor.visit(this),基本上已经形成一种定式了。
  • **结构对象:**一个元素的容器,一般包含一个容纳多个不同类、不同接口的容器,如List、Set、Map等,在项目中一般很少抽象出这个角色。
// 电脑组件
public interface ComputerComponent {
    // 售价
    int price();
    // 硬件版本
    String version();
    // 描述
    String desc();
    void accept(Visitor visitor);
}
// CPU
public class Cpu implements ComputerComponent {
    // 全国标准售价
    public int price = 100;
    @Override
    public int price() {
        return 100;
    }
    @Override
    public String version() {
        return "v1";
    }
    @Override
    public String desc() {
        return "英特尔CPU";
    }
    @Override
    public void accept(Visitor visitor) {
        visitor.visitorCpu(this);
    }
}
// 访问者接口
public interface Visitor {
    // 访问者CPU价格
    void visitorCpu(Cpu cpu);
    // 访问者内存价格
    void visitorMemory(Memory memory);
    // 获得总价
    int price();
    // 访问者名称
    String visiterName();
}
// 学生用户
public class StudentVisitor implements Visitor {
    // 总售价
    public int totalPrice;
    @Override
    public void visitorCpu(Cpu cpu) {
        totalPrice += cpu.price() * 0.8;
    }
    @Override
    public void visitorMemory(Memory memory) {
        totalPrice += memory.price() * 0.9;
    }
    @Override
    public int price() {
        return totalPrice;
    }
    @Override
    public String visiterName() {
        return "学生用户";
    }
}
// 电脑类
public class Computer {
    private ComputerComponent memory;
    private ComputerComponent cpu;
    public Computer() {
        memory = new Memory();
        cpu = new Cpu();
    }
    /**
     * 攒机方法
     *
     * @Visitor 买电脑的客户角色
     */
    public void buildComputer(Visitor visitor) {
        // 买cpu
        cpu.accept(visitor);
        // 买内存
        memory.accept(visitor);
    }
}

public class VisitorTest {
    public static void main(String[] args) {
        Computer computer = new Computer();
        Visitor personVisitor = new PersonVisitor();
        Visitor studentVisitor = new StudentVisitor();
        Visitor companyVisitor = new CompanyVisitor();
        computer.buildComputer(personVisitor);
        System.out.println(String.format("针对%s,每台电脑售价为:%s元", personVisitor.visiterName(), personVisitor.price()));

        computer.buildComputer(studentVisitor);
        System.out.println(String.format("针对%s,每台电脑售价为:%s元", studentVisitor.visiterName(), studentVisitor.price()));

        computer.buildComputer(companyVisitor);
        System.out.println(String.format("针对%s,每台电脑售价为:%s元", companyVisitor.visiterName(), companyVisitor.price()));
    }
}

备忘录(Memento)

定义:在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态,这样以后就可以将该对象回复到原先保存的状态。当你需要让对象返回之前的状态时,就使用备忘录模式。

备忘录模式的结构

  • **发起人:**记录当前时刻的内部状态,负责定义哪些属于备份范围的状态,负责创建和恢复备忘录数据。
  • **备忘录:**负责存储发起人对象的内部状态,在需要的时候提供发起人需要的内部状态。
  • **管理角色:**对备忘录进行管理,保存和提供备忘录。
// 备忘录
@AllArgsConstructor
@NoArgsConstructor
@Data
public class Memento {
    // 文档内容
    public String content;
}

/**
 * 文档类
 **/
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Document {
    // 文档的内容
    private String content;
    public void print() {
        System.out.println("content=" + content);
    }
}

/**
 * @description 备忘录管理类
 */
public class MementoManager {
    // 记录备忘录信息
    private Stack<Memento> mementoStack = new Stack<>();
    // 保存备忘录
    public void save(Document document) {
        Memento memento = new Memento(document.getContent());
        mementoStack.add(memento);
    }
    // 撤销操作ctrl+z
    public Document cancel() {
        Memento memento = mementoStack.pop();
        Document document = new Document();
        document.setContent(memento.getContent());
        return document;
    }
}

/**
 * 备忘录测试类
 */
public class MementoTest {
    public static void main(String[] args) {
        MementoManager mementoManager = new MementoManager();
        System.out.println("-----执行文档修改操作-----");
        Document document = new Document();
        document.setContent("a");
        document.print();
        mementoManager.save(document);

        document.setContent("b");
        document.print();
        mementoManager.save(document);

        document.setContent("c"); // 修改后,发现写错了,想要回撤到上一个保存点
        document.print();

        System.out.println("-----执行第一次撤销操作-----");
        document = mementoManager.cancel();
        document.print();

        System.out.println("-----执行第二次撤销操作-----");
        document = mementoManager.cancel();
        document.print();
    }
}

补充知识点

行为设计模式

解释器(Interpreter)

定义:定义了一个语言的文法,并且建立一个解释器来解释语言中的句子。

解释器模式主要包含以下几个角色:

  • 抽象表达式:声明了抽象的解释操作。
  • 终结符表达式:抽象表达式的子类,实现了与文法中终结符相关的解释操作,文法中的每一个终结符都有一个终结表达式。
  • 非终结符表达式:抽象表达式的子类,实现了文法中非终结符相关的解释操作,由于在非终结符表达式中可以包含终结符表达式也可以包含非终结符表达式,因此解释操作一般是递归完成。         Context(环境):用于存储解释器之外的全局信息。

优点:

  1. 可以通过继承等方式改变和扩展文法。
  2. 每一个文法都可以表示为一个类,可以方便的实现一个语言。
  3. 方便的增加新的解释表达式。

缺点:

  1. 对于复杂的文法可能需要定义过多的解释类,难以维护。
  2. 执行效率低下,解释器模式中使用大量的循环和递归调用,对于复杂的文法执行效率低。
  • 27
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
设计模式是在软件设计过程中,对于常见问题的解决方案的总结和模板化的提炼。Java语言中广泛应用的设计模式有23,分为三个大类:创建型模式、结构型模式和行为型模式。 首先是创建型模式,包括单例模式、简单工厂模式、工厂方法模式、抽象工厂模式、建造者模式和原型模式。单例模式确保一个类只有一个实例化对象,简单工厂模式通过一个工厂类来创建对象,工厂方法模式通过使用工厂接口来创建对象,抽象工厂模式为一个产品族提供创建对象的接口,建造者模式逐步构建一个复杂对象,原型模式通过复制现有对象来创建新对象。 其次是结构型模式,包括适配器模式、桥接模式、装饰器模式、组合模式、外观模式、享元模式和代理模式。适配器模式用于将一个接口转换成客户端所期待的接口,桥接模式将抽象和实现解耦,装饰器模式动态地给对象添加额外职责,组合模式将对象组合成树形结构以表示“部分-整体”的层次结构,外观模式提供了一个简化客户端调用复杂子系统的接口,享元模式通过共享对象来有效地支持大量细粒度的对象,代理模式为其他对象提供一代理以控制对这个对象的访问。 最后是行为型模式,包括模板方法模式、命令模式、迭代器模式、观察者模式、中介者模式、备忘录模式、解释器模式、状态模式、策略模式和访问者模式。模板方法模式定义一个操作中的算法的骨架,而将一些步骤延迟到子类中实现,命令模式将请求封装成一个对象,以使不同的请求能够参数化客户端对象,迭代器模式提供一访问容器对象中各个元素的方式,观察者模式定义了对象之间的一对多依赖,中介者模式用一个中介对象来封装一系列对象的交互,备忘录模式在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态,解释器模式给定一个语言,定义它的文法的一表示,并定义一个解释器,状态模式允许一个对象在其内部状态改变时改变它的行为,策略模式定义了算法家族,分别封装起来,让它们之间可以互相替换,以使得算法的变化不影响到使用算法的客户,访问者模式可以在不改变数据结构的前提下,定义作用于这个结构元素的新操作。通过使用这些设计模式,可以提高软件系统的可维护性、可扩展性和可重用性。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值