面向对象设计模式详解(Java版)----三大类

1. 适配器模式

说明:将一个类的接口转换成客户期望的另一个接口,使不兼容的类能协同工作。像电源转接头,常见于复用旧接口或整合第三方库。
作用:接口转换,让不兼容的类协同工作。
场景:旧系统接口适配,不同格式数据转换,充电器转接头。
关键点:类适配器(继承)与对象适配器(组合),目标接口、适配者与适配器三者协作。

代码示例(第三方外卖接口适配)

interface OrderSystem {
    void submitOrder(String item);
}

class LegacyThirdPartyAPI {
    public void sendRequest(String data) {
        System.out.println("发送:" + data);
    }
}

class OrderAdapter implements OrderSystem {
    private LegacyThirdPartyAPI api = new LegacyThirdPartyAPI();

    public void submitOrder(String item) {
        api.sendRequest("{\"food\":\"" + item + "\"}");
    }
}

public class AdapterDemo {
    public static void main(String[] args) {
        OrderSystem os = new OrderAdapter();
        os.submitOrder("汉堡");  // 发送:{"food":"汉堡"}
    }
}

2. 装饰器模式

说明:动态地给对象附加额外职责,是继承的有力替代。通过包装层层叠加功能,避免为每种组合创建子类,如Java I/O流中套接缓冲功能。
作用:动态添加功能,比继承更灵活。
场景:Java I/O流(BufferedReader包装FileReader),咖啡加料(牛奶或糖)。
关键点:抽象组件、具体组件、装饰器抽象类与具体装饰器,支持嵌套包装。

代码示例(汉堡加料)

interface Burger {
    String getDesc();
    double getPrice();
}

class PlainBurger implements Burger {
    public String getDesc() {
        return "汉堡";
    } 
    public double getPrice() {
        return 10;
    }
}

abstract class ToppingDecorator implements Burger {
    protected Burger burger;
}

class Cheese extends ToppingDecorator {
    public Cheese(Burger b) {
        this.burger = b;
    }
    public String getDesc() {
        return burger.getDesc() + "+芝士";
    }
    public double getPrice() {
        return burger.getPrice() + 2;
    }
}

public class DecoratorDemo {
    public static void main(String[] args) {
        Burger burger = new Cheese(new PlainBurger());
        // 汉堡+芝士 价格:12.0
        System.out.println(burger.getDesc() + " 价格:" + burger.getPrice());  
    }
}

3. 代理模式

说明:为对象提供替身以控制对该对象的访问。可延迟加载大对象、检查访问权限或记录日志,与装饰器外观相似但侧重控制而非增强。
作用:控制对象访问,延迟加载,权限校验。
场景:虚拟代理(图片懒加载),保护代理(权限控制),远程代理(RPC)。
关键点:抽象主题、真实主题与代理类,JDK动态代理或CGLIB,区分控制与增强。

代码示例(点餐权限控制)

interface OrderService {
    void order(String food);
}

class RealOrderService implements OrderService {
    public void order(String food) {
        System.out.println("下单:" + food);
    }
}

class OrderProxy implements OrderService {

    private RealOrderService real = new RealOrderService();

    private String userRole;

    public OrderProxy(String role) {
        this.userRole = role;
    }
    public void order(String food) {
        if ("VIP".equals(userRole)){
            real.order(food);
        }else{
            System.out.println("无权限");
        }
    }
}

public class ProxyDemo {
    public static void main(String[] args) {
        OrderService os = new OrderProxy("VIP");
        os.order("汉堡");  // 下单:汉堡
        OrderService os2 = new OrderProxy("普通");
        os2.order("汉堡"); // 无权限
    }
}

4. 外观模式

说明:为复杂子系统提供统一简化的高层接口,隐藏内部混乱依赖。客户端只与外观交互,降低使用门槛,如一键拍照封装调焦、曝光等步骤。
作用:简化复杂子系统调用,降低耦合。
场景:复杂第三方库封装,MVC中的Service层,一键电脑启动。
关键点:外观类(门面)与多个子系统类,不封装子系统内部逻辑,体现迪米特法则。

代码示例(一键点餐)

class Grill {
    void grillMeat() {
        System.out.println("烤肉");
    }
}

class Fry {
    void fryPotato() {
        System.out.println("炸薯条");
    }
}

class Pour {
    void pourDrink() {
        System.out.println("倒可乐");
    }
}

class OrderFacade {
    private Grill grill = new Grill();
    private Fry fry = new Fry();
    private Pour pour = new Pour();

    public void makeMeal() {
        grill.grillMeat();
        fry.fryPotato();
        pour.pourDrink();
        System.out.println("套餐完成");
    }
}

public class FacadeDemo {
    public static void main(String[] args) {
        OrderFacade facade = new OrderFacade();
        facade.makeMeal();
        // 烤肉 炸薯条 倒可乐 套餐完成
    }
}

5. 桥接模式

说明:将抽象部分与实现部分分离,使两者可独立变化而不互相影响。通过组合代替多维度继承,解决类爆炸问题,如不同形状与颜色的自由组合。
作用:分离抽象与实现,独立变化,避免类爆炸。
场景:跨平台应用(不同系统下不同形状窗口),遥控器与设备。
关键点:抽象类持有实现接口引用,组合优于继承,两个独立变化维度。

代码示例(餐品与口味分离)

interface Flavor {
    String getFlavor();
}

class Spicy implements Flavor {
    public String getFlavor() {
        return "辣味";
    }
}

class Sweet implements Flavor {
    public String getFlavor() {
        return "甜味";
    }
}

abstract class Food {
    protected Flavor flavor;

    Food(Flavor f) {
        this.flavor = f;
    }

    abstract String getName();
}

class ChickenWing extends Food {

    public ChickenWing(Flavor f) {
        super(f);
    }

    String getName() {
        return flavor.getFlavor() + "鸡翅"; 
    }
}

public class BridgeDemo {
    public static void main(String[] args) {
        Food food = new ChickenWing(new Spicy());
        System.out.println(food.getName());  // 辣味鸡翅
    }
}

6. 组合模式

说明:将对象组织成树形结构以表示部分‑整体层次,让客户端统一对待单个对象和组合对象。典型如文件系统中文件夹与文件操作无差异。
作用:统一处理叶子节点与容器节点,表示树形结构。
场景:文件系统(文件与文件夹),UI布局(容器与控件),组织架构树。
关键点:组件抽象类(统一操作),叶子节点与容器节点(持有子节点列表),透明模式或安全模式。

代码示例(套餐组合)

import java.util.*;
interface MealItem {
    double getPrice();
}

class SingleItem implements MealItem {
    private double price;

    SingleItem(double p) {
        price = p;
    }
    public double getPrice() {
        return price;
    }
}

class Combo implements MealItem {
    private List<MealItem> items = new ArrayList<>();

    public void add(MealItem item) {
        items.add(item);
    }
    public double getPrice() {
        return items.stream().mapToDouble(MealItem::getPrice).sum() * 0.9;
    }
}

public class CompositeDemo {
    public static void main(String[] args) {
        Combo combo = new Combo();
        combo.add(new SingleItem(10));
        combo.add(new SingleItem(8));
        System.out.println("套餐价格:" + combo.getPrice());  // 套餐价格:16.2
    }
}

7. 享元模式

说明:通过共享技术高效支持大量细粒度对象,减少内存占用。区分可共享的内部状态与随环境变化的外部状态,如文本编辑器复用相同字符对象。
作用:减少内存占用,共享细粒度对象。
场景:文本编辑器字符对象,游戏子弹或树木,线程池中的线程。
关键点:区分内部状态(共享)与外部状态(不共享),享元工厂管理对象池。

代码示例(汉堡配料共享)

import java.util.*;

class Ingredient {
    private String name;

    Ingredient(String n) {
        name = n;
    }
    public String getName() {
        return name;
    }
}

class IngredientFactory {
    private static Map<String, Ingredient> pool = new HashMap<>();

    public static Ingredient get(String name) {
        if (!pool.containsKey(name)) {
            pool.put(name, new Ingredient(name));
        }
        return pool.get(name);
    }
}

public class FlyweightDemo {
    public static void main(String[] args) {
        Ingredient cheese1 = IngredientFactory.get("芝士");
        Ingredient cheese2 = IngredientFactory.get("芝士");
        System.out.println(cheese1 == cheese2);  // true
    }
}

更多推荐