前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >设计模式

设计模式

原创
作者头像
羽毛球初学者
发布2024-10-17 16:30:58
900
发布2024-10-17 16:30:58
举报
文章被收录于专栏:JAVA基础知识

单例模式

单例模式是一种常用的设计模式,在应用这个模式时,单例对象的类必须保证只有一个实例存在,整个系统只能使用一个对象实例。这样做的优点是不会频繁地创建和销毁对象,浪费资源。通常在IO操作、数据库连接或者Redis连接等场景下使用。

代码语言:java
复制
// 1、普通单例模式:项目一启动就初始化,不管之后用没用到。
class Singleton {
    private static Singleton instance = new Singleton();
    public static Singleton getInstance() {
        return instance;
    }
}

// 2、延迟加载单例模式:在实际使用到的时候才去初始化,避免浪费。
class SingletonLazy {
    private static SingletonLazy instance;
    public static SingletonLazy getInstance() {
        if (instance == null) {
            instance = new SingletonLazy();
        }
        return instance;
    }
}

// 3、线程安全的单例模式:通过加锁控制,保证在多线程调用时保障只有一个实例化对象。
class SingletonLazy {
    private static SingletonLazy instance;
    public static synchronized SingletonLazy getInstance() {
        if (instance == null) {
            instance = new SingletonLazy();
        }
        return instance;
    }

工厂模式

简单工厂模式

简单工厂模式又叫静态工厂方法模式,就是建立一个工厂类,对实现了同一接口的一些类进行实例的创建。比如,一台咖啡机就可以理解为一个工厂模式,你只需要按下想喝的咖啡品类的按钮(摩卡或拿铁),它就会给你生产一杯相应的咖啡,你不需要管它内部的具体实现,只要告诉它你的需求即可。简单工厂模式中包含的角色及其相应的职责如下:

  • 工厂角色:这是简单工厂模式的核心,由它负责创建所有的类的内部逻辑。当然工厂类必须能够被外界调用,创建所需要的产品对象。
  • 抽象产品角色:简单工厂模式所创建的所有对象的父类,注意,这里的父类可以是接口也可以是抽象类,它负责描述所有实例所共有的公共接口。
  • 具体产品角色:简单工厂所创建的具体实例对象,这些具体的产品往往都拥有共同的父类。

简单工厂模式的优点有 :

  • 工厂类含有必要的判断逻辑,客户端可以免除直接创建产品对象的责任,直接使用即可。
  • 客户端无须知道所创建的具体产品类的类名,只需要知道具体产品类所对应的参数即可。

缺点有:

  • 不易拓展,一旦添加新的产品类型,就不得不修改工厂的创建逻辑;
  • 产品类型较多时,工厂的创建逻辑可能过于复杂,一旦出错可能造成所有产品的创建失败,不利于系统的维护。
代码语言:java
复制
// 简单工厂模式示例代码
package MyTest;

// 定义动物的接口 
interface Animal { 
    public void say(); // 说话方法 
}
class Cat implements Animal {
    @Override
    public void say() {
        System. out .println("我是猫咪,喵呜!" );
    }
}
class Dog implements Animal {
    @Override
    public void say() {
        System. out .println("我是小狗,汪汪!" );
    }
}

// 定义工厂类 
class Factory { 
    public static Animal getInstance(String className) {
        Animal a = null ; // 定义接口对象 
        if ("Cat" .equals(className)) {
            a = new Cat(); // 通过Cat子类实例化接口 
        }
        if ("Dog" .equals(className)) {
           a = new Dog(); // 通过Dog子类实例化接口 
        }
        return a ;
    }
}

public class FactoryDemo {
    public static void main(String[] args) {
        Animal cat = null ;
        cat = Factory. getInstance("Cat");
        Animal dog = null ;
        dog = Factory. getInstance("Dog");
        cat.say();
        dog.say();
    }
}

工厂方法模式

工厂方法模式是简单工厂模式的进一步抽象化和推广,工厂方法模式不再只由一个工厂类决定哪一个产品类应当被实例化,这个决定被交给抽象工厂的子类去做。它的具体组成有以下几部分:

  • 抽象工厂角色: 这是工厂方法模式的核心,它与应用程序无关。是具体工厂角色必须实现的接口或者必须继承的父类。在java中它由抽象类或者接口来实现。
  • 具体工厂角色:它含有和具体业务逻辑有关的代码。由应用程序调用以创建对应的具体产品的对象。
  • 抽象产品角色:它是具体产品继承的父类或者是实现的接口。在java中一般有抽象类或者接口来实现。
  • 具体产品角色:具体工厂角色所创建的对象就是此角色的实例。在java中由具体的类来实现。

工厂方法模式使用继承自抽象工厂角色的多个子类来代替简单工厂模式中的“上帝类”。正如上面所说,这样便分担了对象承受的压力,而且这样使得结构变得灵活起来。当有新的产品产生时,只要按照抽象产品角色、抽象工厂角色提供的合同来生成,那么就可以被客户使用,而不必去修改任何已有的代码。

代码语言:java
复制
// 工厂方法模式示例
package MyTest;

// 抽象产品角色
interface Moveable {
    void run();
}
// 具体产品角色
class Plane implements Moveable {
    @Override
    public void run() {
        System. out .println("plane...." );
    }
}
class Broom implements Moveable {
    @Override
    public void run() {
        System. out .println("broom....." );
    }
}
// 抽象工厂角色
abstract class VehicleFactory {
    abstract Moveable create();
}
// 具体工厂角色
class PlaneFactory extends VehicleFactory{
    public Moveable create() {
        return new Plane();
    }
}
class BroomFactory extends VehicleFactory{
    public Moveable create() {
        return new Broom();
    }
}

public class FactoryDemo {
    public static void main(String[] args) {
        VehicleFactory factory = new BroomFactory();
        Moveable m = factory.create();
        m.run();
    }
}

抽象工厂模式

抽象工厂模式提供一个创建一系列相关或依赖对象的接口,无需指定具体类。在抽象工厂模式中,抽象产品 (AbstractProduct) 可能是一个或多个,从而构成一个或多个产品族(Product Family)。 在只有一个产品族的情况下,抽象工厂模式实际上退化到工厂方法模式。

代码语言:java
复制
// 抽象工厂模式示例
package MyTest;

// 抽象产品
abstract class Vehicle{
    public abstract void run();
}
// 具体产品
class Bike extends Vehicle{
    @Override
    public void run() {
        System. out .println("bike run..." );
    }
}
class Weapon{
    public void shoot(){
        System. out .println("weapon shoot..." );
    }
}
class Food{
    public void getName(){
        System. out .println("food..." );
    }
}
//抽象工厂类
abstract class AbstractFactory {
    public abstract Vehicle createVehicle();
    public abstract Weapon createWeapon();
    public abstract Food createFood();
}
//具体工厂类
class DefaultFactory extends AbstractFactory{
    @Override
    public Vehicle createVehicle() {
        return new Bike();
    }
    @Override
    public Weapon createWeapon() {
        return new Weapon();
    }
    @Override
    public Food createFood() {
        return new Food();
    }
}
//测试类
public class FactoryDemo {
    public static void main(String[] args) {
        AbstractFactory f = new DefaultFactory();
        Vehicle v = f.createVehicle();
        v.run();
        Weapon w = f.createWeapon();
        w.shoot();
        Food a = f.createFood();
        a.getName();
    }
}

观察者模式

观察者模式是定义对象间的一种一对多依赖关系,使得每当一个对象状态发生改变时,其相关依赖对象皆得到通知并被自动更新。观察者模式又叫做发布-订阅(Publish/Subscribe)模式,它有以下优点 :

  • 观察者模式可以实现表示层和数据逻辑层的分离,并定义了稳定的消息更新传递机制,抽象了更新接口,使得可以有各种各样不同的表示层作为具体观察者角色;
  • 观察者模式在观察目标和观察者之间建立一个抽象的耦合;
  • 观察者模式支持广播通信;
  • 观察者模式符合开闭原则(对拓展开放,对修改关闭)的要求。

缺点如下:

  • 如果一个观察目标对象有很多直接和间接的观察者的话,将所有的观察者都通知到会花费很多时间;
  • 如果在观察者和观察目标之间有循环依赖的话,观察目标会触发它们之间进行循环调用,可能导致系统崩溃;
  • 观察者模式没有相应的机制让观察者知道所观察的目标对象是怎么发生变化的,而仅仅只是知道观察目标发生了变化。
代码语言:java
复制
// 观察者模式示例

// 观察者(消息接收方)
interface Observer {
    public void update(String message);
}

/*
 * 具体的观察者(消息接收方)
 */
class ConcrereObserver implements Observer {
    private String name;
 
    public ConcrereObserver(String name) {
        this.name = name;
    }
 
    @Override
    public void update(String message) {
        System.out.println(name + ":" + message);
    }
}

/*
 * 被观察者(消息发布方)
 */
interface Subject {
    // 增加订阅者
    public void attach(Observer observer);
    // 删除订阅者
    public void detach(Observer observer);
    // 通知订阅者更新消息
    public void notify(String message);
}
/*
 * 具体被观察者(消息发布方)
 */
class ConcreteSubject implements Subject {
    // 订阅者列表
    private List<Observer> list = new ArrayList<Observer>();
    @Override
    public void attach(Observer observer) {
        list.add(observer);
    }
    @Override
    public void detach(Observer observer) {
        list.remove(observer);
    }
    @Override
    public void notify(String message) {
        for (Observer observer : list) {
            observer.update(message);
        }
    }
}

public class ObserverTest {
    public static void main(String[] args) {
        // 定义发布者
        ConcreteSubject concreteSubject = new ConcreteSubject();
        // 定义订阅者
        ConcrereObserver concrereObserver = new ConcrereObserver("老王");
        ConcrereObserver concrereObserver2 = new ConcrereObserver("Java");
        // 添加订阅
        concreteSubject.attach(concrereObserver);
        concreteSubject.attach(concrereObserver2);
        // 发布信息
        concreteSubject.notify("更新了");
    }
}

装饰器模式

装饰器模式是指动态地给一个对象增加一些额外的功能,同时又不改变其结构。装饰类和被装饰类可以独立发展,不会相互耦合,装饰模式是继承的一个替代模式,装饰模式可以动态扩展一个实现类的功能。

代码语言:java
复制
// 装饰器模式示例

/**
 * 咖啡接口
 */
interface Coffee {
    String getDescription();
    double getCost();
}

/**
 * 黑咖啡
 */
class BlackCoffee implements Coffee {
    @Override
    public String getDescription() {
        return "黑咖啡";
    }

    @Override
    public double getCost() {
        return 2.0;
    }
}

/**
 * 咖啡装饰器抽象类
 */
abstract class CoffeeDecorator implements Coffee {
    protected Coffee coffee;

    public CoffeeDecorator(Coffee coffee) {
        this.coffee = coffee;
    }

    @Override
    public String getDescription() {
        return coffee.getDescription();
    }

    @Override
    public double getCost() {
        return coffee.getCost();
    }
}

/**
 * 糖装饰器
 */
class SugarDecorator extends CoffeeDecorator {
    public SugarDecorator(Coffee coffee) {
        super(coffee);
    }

    @Override
    public String getDescription() {
        return super.getDescription() + ", 加糖";
    }

    @Override
    public double getCost() {
        return super.getCost() + 0.3;
    }
}

/**
 * 奶装饰器
 */
class MilkDecorator extends CoffeeDecorator {
    public MilkDecorator(Coffee coffee) {
        super(coffee);
    }

    @Override
    public String getDescription() {
        return super.getDescription() + ", 加牛奶";
    }

    @Override
    public double getCost() {
        return super.getCost() + 0.5;
    }
}

public class Main {
    public static void main(String[] args) {
        // 订一杯黑咖啡
        Coffee coffee = new BlackCoffee();
        System.out.println("订单:" + coffee.getDescription());
        System.out.println("总价:" + coffee.getCost());

        // 加牛奶
        coffee = new MilkDecorator(coffee);
        System.out.println("订单:" + coffee.getDescription());
        System.out.println("总价:" + coffee.getCost());

        // 再加糖
        coffee = new SugarDecorator(coffee);
        System.out.println("订单:" + coffee.getDescription());
        System.out.println("总价:" + coffee.getCost());
    }
}

模板方法模式

模板方法模式是指定义一个模板结构,将具体内容延迟到子类去实现,它有以下优点 :

  • 提高代码复用性:将相同部分的代码放在抽象的父类中,而将不同的代码放入不同的子类中;
  • 实现了反向控制:通过一个父类调用其子类的操作,通过对子类的具体实现扩展不同的行为,实现了反向控制并且符合开闭原则。
代码语言:java
复制
// 模板方法模式示例

// 抽象模板
public abstract class AbstractCook {
    public final void doCook(){
        openFire();
        cooking();
        closeFire();
    }
    
    protected void openFire() {
        System.out.println("点火,开始做菜了");
    }
    
    // 具体菜品的烹饪方式不一样,留给子类去实现
    protected abstract void cooking();
    
    protected void closedFire() {
        System.out.println("关火,菜出锅了");
    }
}

// 具体子类
public class cookFish extends AbstractCook {
    @Override
    protected void cooking() {
        System.out.println("一份鱼!");
    }
}

public class cookRice extends AbstractCook {
    @Override
    protected void cooking() {
        System.out.println("一份饭!");
    }
}

public class TemplateMethodPatternTest {
    public static void main(String[] args) {
        AbstractCook fish = new cookFish();
        fish.doCook();
        System.out.println("===========");
        FryRice rice = new cookRice();
        fryRice.doCook();

    }
}

代理模式

代理模式是给某一个对象提供一个代理,并由代理对象控制对原对象的引用。

优点 :

  • 代理模式能够协调调用者和被调用者,在一定程度上降低了系统的耦合度;
  • 可以灵活地隐藏被代理对象的部分功能和服务,也增加额外的功能和服务。

缺点 :

  • 由于使用了代理模式,因此程序的性能没有直接调用性能高;
  • 使用代理模式提高了代码的复杂度。

代理模式可分为静态代理(Static Proxy)、动态代理(Dynamic Proxy)和 CGLIB代理(Code Generation Library Proxy)。

静态代理

静态代理是在代码编译阶段就已经生成了代理类,代理类需要实现与目标对象相同的接口。它可以在不修改目标对象的前提下对目标对象的方法进行增强,但是需要为每个目标对象创建一个代理类,导致系统中类的数量增加,维护成本较高。

代码语言:java
复制
// 静态代理示例

// 抽象接口
public interface Service {
    void performOperation();
}
 
// 目标对象
public class RealService implements Service {
    public void performOperation() {
        System.out.println("Performing operation in RealService");
    }
}
 
// 代理对象
public class ServiceProxy implements Service {
    private RealService realService;
 
    public ServiceProxy(RealService realService) {
        this.realService = realService;
    }
 
    public void performOperation() {
        System.out.println("Proxy: Before operation");
        realService.performOperation();
        System.out.println("Proxy: After operation");
    }
}
 
// 客户端代码
public class Client {
    public static void main(String[] args) {
        RealService realService = new RealService();
        Service proxy = new ServiceProxy(realService);
        proxy.performOperation();
    }
}

动态代理

动态代理是在程序运行时,通过反射机制动态生成的代理类。Java提供了 java.lang.reflect.Proxy 类来实现动态代理。它的优点有:

  • 可以为多个目标对象创建一个代理类,减少了类的数量。
  • 代理类的生成是在运行时完成的,可以更加灵活地处理不同的情况。

但是由于使用了反射机制,性能相对静态代理略低。

代码语言:java
复制
// 动态代理示例

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
 
// 抽象接口
public interface Service {
    void performOperation();
}
 
// 目标对象
public class RealService implements Service {
    public void performOperation() {
        System.out.println("Performing operation in RealService");
    }
}
 
// 动态代理处理器
public class ServiceInvocationHandler implements InvocationHandler {
    private Object target;
 
    public ServiceInvocationHandler(Object target) {
        this.target = target;
    }
 
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("Proxy: Before operation");
        Object result = method.invoke(target, args);
        System.out.println("Proxy: After operation");
        return result;
    }
}
 
// 客户端代码
public class Client {
    public static void main(String[] args) {
        RealService realService = new RealService();
        ServiceInvocationHandler handler = new ServiceInvocationHandler(realService);
        Service proxy = (Service) Proxy.newProxyInstance(realService.getClass().getClassLoader(),
                                                         new Class<?>[]{Service.class},
                                                         handler);
        proxy.performOperation();
    }
}

CGLIB 代理

CGLIB代理是通过继承目标对象的方式来创建代理类。它是第三方库(如Spring AOP)常用的一种代理方式,适用于没有实现接口的类。CGLIB代理不需要目标对象实现接口,可以代理任何类。由于采用了继承的方式,所以需要注意目标类不能是 final 类,代理类也不能是 final 方法。相对于 JDK 的动态代理,CGLIB代理的性能较高,但由于使用了字节码生成技术,可能会增加复杂性。

代码语言:java
复制
// CGLIB代理示例

import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;
 
import java.lang.reflect.Method;
 
// 目标对象
public class RealService {
    public void performOperation() {
        System.out.println("Performing operation in RealService");
    }
}
 
// CGLIB代理
public class CglibProxy implements MethodInterceptor {
    private Object target;
 
    public CglibProxy(Object target) {
        this.target = target;
    }
 
    public Object createProxy() {
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(target.getClass());
        enhancer.setCallback(this);
        return enhancer.create();
    }
 
    public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
        System.out.println("Proxy: Before operation");
        Object result = proxy.invokeSuper(obj, args);
        System.out.println("Proxy: After operation");
        return result;
    }
}
 
// 客户端代码
public class Client {
    public static void main(String[] args) {
        RealService realService = new RealService();
        CglibProxy proxy = new CglibProxy(realService);
        RealService proxyService = (RealService) proxy.createProxy();
        proxyService.performOperation();
    }
}

策略模式

策略模式是指定义一系列算法,将每个算法都封装起来,并且使他们之间可以相互替换。它遵循了开闭原则,扩展性良好,但随着策略的增加,对外暴露的也会越来越多。

代码语言:java
复制
// 策略模式示例

/*
 * 声明旅行
 */
interface ITrip {
    void going();
}
class Bike implements ITrip {
    @Override
    public void going() {
        System.out.println("骑自行车");
    }
}
class Drive implements ITrip {
    @Override
    public void going() {
        System.out.println("开车");
    }
}
/*
 * 定义出行类
 */
class Trip {
    private ITrip trip;
 
    public Trip(ITrip trip) {
        this.trip = trip;
    }
 
    public void doTrip() {
        this.trip.going();
    }
}


public class StrategyTest {
    public static void main(String[] args) {
        Trip trip = new Trip(new Bike());
        trip.doTrip();
    }
}

适配器模式

适配器模式是将一个类的接口变成客户端所期望的另一种接口,从而使原本因接口不匹配而无法一起工作的两个类能够在一起工作。它灵活性好,不会破坏原有的系统。但是如果过多地使用适配器,容易使代码结构混乱(如明明看到调用的是 A 接口,内部调用的却是 B 接口的实现)。

代码语言:java
复制
// 适配器模式示例

/*
 * 传统的充电线 MicroUSB
 */
interface MicroUSB {
    void charger();
}
/*
 * TypeC 充电口
 */
interface ITypeC {
    void charger();
}
class TypeC implements ITypeC {
    @Override
    public void charger() {
        System.out.println("TypeC 充电");
    }
}
/*
 * 适配器
 */
class AdapterMicroUSB implements MicroUSB {
    private TypeC typeC;
 
    public AdapterMicroUSB(TypeC typeC) {
        this.typeC = typeC;
    }
 
    @Override
    public void charger() {
        typeC.charger();
    }
}

public class AdapterTest {
    public static void main(String[] args) {
        TypeC typeC = new TypeC();
        MicroUSB microUSB = new AdapterMicroUSB(typeC);
        microUSB.charger();
 
    }
}

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 单例模式
  • 工厂模式
    • 简单工厂模式
      • 工厂方法模式
        • 抽象工厂模式
        • 观察者模式
        • 装饰器模式
        • 模板方法模式
        • 代理模式
          • 静态代理
            • 动态代理
              • CGLIB 代理
              • 策略模式
              • 适配器模式
              相关产品与服务
              云数据库 Redis
              腾讯云数据库 Redis(TencentDB for Redis)是腾讯云打造的兼容 Redis 协议的缓存和存储服务。丰富的数据结构能帮助您完成不同类型的业务场景开发。支持主从热备,提供自动容灾切换、数据备份、故障迁移、实例监控、在线扩容、数据回档等全套的数据库服务。
              领券
              问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档