MK
摩柯社区 - 一个极简的技术知识社区
AI 面试

Java设计模式与面向对象思想

2023-06-202.7k 阅读

面向对象思想基础

面向对象的概念

面向对象编程(Object - Oriented Programming,OOP)是一种编程范式,它将数据(属性)和操作数据的方法(行为)封装在一起形成对象。在现实世界中,任何事物都可以看作是一个对象,例如一辆汽车,它有颜色、型号等属性,也有启动、加速、刹车等行为。在 Java 中,通过类来定义对象的类型,一个类可以创建多个对象实例。

面向对象的特性

  1. 封装 封装是将数据和操作数据的方法组合在一个单元(类)中,并对外部隐藏内部实现细节。这样可以保护数据不被随意修改,同时提供了清晰的接口供其他对象使用。 在 Java 中,通过访问修饰符来实现封装。例如,使用 private 修饰符修饰类的属性,使得该属性只能在类内部被访问。如下代码示例:
class Person {
    private String name;
    private int age;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        if (age > 0) {
            this.age = age;
        }
    }
}

在上述代码中,nameage 属性被声明为 private,外部对象不能直接访问和修改。只能通过 getNamesetNamegetAgesetAge 这些公开的方法来操作属性,在 setAge 方法中还可以进行数据的合法性检查。

  1. 继承 继承允许一个类(子类)从另一个类(父类)获取属性和方法,子类可以复用父类的代码,并且可以在此基础上添加新的属性和方法或者重写父类的方法。继承体现了 “is - a” 的关系,例如,一个 Student 类继承自 Person 类,那么可以说 Student “is - a” Person。 在 Java 中,使用 extends 关键字来实现继承,示例代码如下:
class Person {
    private String name;
    private int age;

    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public int getAge() {
        return age;
    }
}

class Student extends Person {
    private String studentId;

    public Student(String name, int age, String studentId) {
        super(name, age);
        this.studentId = studentId;
    }

    public String getStudentId() {
        return studentId;
    }
}

在上述代码中,Student 类继承了 Person 类,从而拥有了 nameage 属性以及 getNamegetAge 方法。Student 类还添加了自己特有的 studentId 属性和 getStudentId 方法。在 Student 类的构造函数中,使用 super 关键字调用了父类 Person 的构造函数。

  1. 多态 多态是指同一个操作作用于不同的对象,可以有不同的解释,产生不同的执行结果。在 Java 中,多态主要通过方法重写和方法重载来实现。
    • 方法重写:当子类继承父类并对父类中已有的方法进行重新定义时,就发生了方法重写。重写的方法需要满足方法名、参数列表和返回类型与父类中被重写的方法相同(返回类型可以是父类返回类型的子类)。
    • 方法重载:在同一个类中,多个方法可以具有相同的方法名,但参数列表不同(参数个数、参数类型或参数顺序不同),这就是方法重载。

以下是方法重写和方法重载的代码示例:

class Animal {
    public void makeSound() {
        System.out.println("Animal makes a sound");
    }
}

class Dog extends Animal {
    @Override
    public void makeSound() {
        System.out.println("Dog barks");
    }
}

class Cat extends Animal {
    @Override
    public void makeSound() {
        System.out.println("Cat meows");
    }
}

class OverloadingExample {
    public void printInfo(int num) {
        System.out.println("The number is: " + num);
    }

    public void printInfo(String str) {
        System.out.println("The string is: " + str);
    }
}

在上述代码中,DogCat 类重写了 Animal 类的 makeSound 方法,表现出不同的行为。而 OverloadingExample 类展示了方法重载,两个 printInfo 方法具有相同的方法名但参数类型不同。

设计模式概述

设计模式的定义

设计模式是在软件开发过程中,针对反复出现的问题所总结归纳出的通用解决方案。这些解决方案是经过大量实践验证的,能够提高软件的可维护性、可扩展性和可复用性。设计模式并不是具体的代码实现,而是一种思想和原则,不同的编程语言可以根据自身的特点来实现这些设计模式。

设计模式的分类

根据设计模式的目的和用途,通常将其分为三大类:创建型模式、结构型模式和行为型模式。

  1. 创建型模式 创建型模式主要用于对象的创建过程,它隐藏了对象创建的具体细节,使得代码在创建对象时更加灵活和可维护。常见的创建型模式有单例模式、工厂模式、抽象工厂模式、建造者模式和原型模式。
  2. 结构型模式 结构型模式关注如何将类或对象组合成更大的结构,以实现更复杂的功能。它通过改变类或对象之间的组合关系来提高系统的灵活性和可维护性。常见的结构型模式有代理模式、适配器模式、桥接模式、装饰器模式、外观模式、享元模式和组合模式。
  3. 行为型模式 行为型模式主要用于处理对象之间的交互和职责分配,它描述了对象之间如何进行通信和协作,以实现特定的行为。常见的行为型模式有策略模式、模板方法模式、观察者模式、迭代器模式、责任链模式、命令模式、备忘录模式、状态模式、访问者模式、中介者模式和解释器模式。

创建型模式

单例模式

  1. 概念 单例模式确保一个类只有一个实例,并提供一个全局访问点。在一些应用场景中,比如数据库连接池、线程池等,只需要一个实例来管理资源,使用单例模式可以避免资源的重复创建和浪费。
  2. 实现方式
    • 饿汉式:在类加载时就创建实例,线程安全。
public class SingletonEager {
    private static final SingletonEager instance = new SingletonEager();

    private SingletonEager() {
    }

    public static SingletonEager getInstance() {
        return instance;
    }
}
- **懒汉式**:在第一次调用 `getInstance` 方法时才创建实例,但是线程不安全。
public class SingletonLazy {
    private static SingletonLazy instance;

    private SingletonLazy() {
    }

    public static SingletonLazy getInstance() {
        if (instance == null) {
            instance = new SingletonLazy();
        }
        return instance;
    }
}
- **双重检查锁懒汉式**:在懒汉式的基础上,通过双重检查锁来保证线程安全。
public class SingletonDoubleCheck {
    private static volatile SingletonDoubleCheck instance;

    private SingletonDoubleCheck() {
    }

    public static SingletonDoubleCheck getInstance() {
        if (instance == null) {
            synchronized (SingletonDoubleCheck.class) {
                if (instance == null) {
                    instance = new SingletonDoubleCheck();
                }
            }
        }
        return instance;
    }
}
- **静态内部类方式**:利用类加载机制来保证线程安全,同时又能实现延迟加载。
public class SingletonInnerClass {
    private SingletonInnerClass() {
    }

    private static class SingletonHolder {
        private static final SingletonInnerClass INSTANCE = new SingletonInnerClass();
    }

    public static SingletonInnerClass getInstance() {
        return SingletonHolder.INSTANCE;
    }
}

工厂模式

  1. 概念 工厂模式将对象的创建和使用分离,通过一个工厂类来负责创建对象。这样可以提高代码的可维护性和可扩展性,当需要创建新的对象时,只需要修改工厂类,而不需要修改使用对象的代码。
  2. 简单工厂模式 简单工厂模式是工厂模式的基础,它定义了一个工厂类,用于创建产品对象。虽然简单工厂模式不属于 GoF 23 种设计模式之一,但它是理解其他工厂模式的基础。
class Product {
    public void use() {
        System.out.println("Using product");
    }
}

class SimpleFactory {
    public Product createProduct() {
        return new Product();
    }
}

public class SimpleFactoryExample {
    public static void main(String[] args) {
        SimpleFactory factory = new SimpleFactory();
        Product product = factory.createProduct();
        product.use();
    }
}
  1. 工厂方法模式 工厂方法模式在简单工厂模式的基础上,将工厂类的创建方法抽象成抽象方法,由具体的子类工厂来实现创建不同的产品。
abstract class Product {
    public abstract void use();
}

class ConcreteProduct1 extends Product {
    @Override
    public void use() {
        System.out.println("Using ConcreteProduct1");
    }
}

class ConcreteProduct2 extends Product {
    @Override
    public void use() {
        System.out.println("Using ConcreteProduct2");
    }
}

abstract class Factory {
    public abstract Product createProduct();
}

class ConcreteFactory1 extends Factory {
    @Override
    public Product createProduct() {
        return new ConcreteProduct1();
    }
}

class ConcreteFactory2 extends Factory {
    @Override
    public Product createProduct() {
        return new ConcreteProduct2();
    }
}

public class FactoryMethodExample {
    public static void main(String[] args) {
        Factory factory1 = new ConcreteFactory1();
        Product product1 = factory1.createProduct();
        product1.use();

        Factory factory2 = new ConcreteFactory2();
        Product product2 = factory2.createProduct();
        product2.use();
    }
}
  1. 抽象工厂模式 抽象工厂模式提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类。
abstract class AbstractProductA {
    public abstract void interact(AbstractProductB productB);
}

abstract class AbstractProductB {
    public abstract void interact(AbstractProductA productA);
}

class ProductA1 extends AbstractProductA {
    @Override
    public void interact(AbstractProductB productB) {
        System.out.println(this.getClass().getName() + " interacts with " + productB.getClass().getName());
    }
}

class ProductA2 extends AbstractProductA {
    @Override
    public void interact(AbstractProductB productB) {
        System.out.println(this.getClass().getName() + " interacts with " + productB.getClass().getName());
    }
}

class ProductB1 extends AbstractProductB {
    @Override
    public void interact(AbstractProductA productA) {
        System.out.println(this.getClass().getName() + " interacts with " + productA.getClass().getName());
    }
}

class ProductB2 extends AbstractProductB {
    @Override
    public void interact(AbstractProductA productA) {
        System.out.println(this.getClass().getName() + " interacts with " + productA.getClass().getName());
    }
}

abstract class AbstractFactory {
    public abstract AbstractProductA createProductA();
    public abstract AbstractProductB createProductB();
}

class ConcreteFactory1 extends AbstractFactory {
    @Override
    public AbstractProductA createProductA() {
        return new ProductA1();
    }

    @Override
    public AbstractProductB createProductB() {
        return new ProductB1();
    }
}

class ConcreteFactory2 extends AbstractFactory {
    @Override
    public AbstractProductA createProductA() {
        return new ProductA2();
    }

    @Override
    public AbstractProductB createProductB() {
        return new ProductB2();
    }
}

public class AbstractFactoryExample {
    public static void main(String[] args) {
        AbstractFactory factory1 = new ConcreteFactory1();
        AbstractProductA productA1 = factory1.createProductA();
        AbstractProductB productB1 = factory1.createProductB();
        productA1.interact(productB1);

        AbstractFactory factory2 = new ConcreteFactory2();
        AbstractProductA productA2 = factory2.createProductA();
        AbstractProductB productB2 = factory2.createProductB();
        productA2.interact(productB2);
    }
}

结构型模式

代理模式

  1. 概念 代理模式为其他对象提供一种代理以控制对这个对象的访问。代理对象可以在客户端和目标对象之间起到中介作用,在访问目标对象之前或之后执行一些额外的操作,比如权限验证、日志记录等。
  2. 静态代理 静态代理需要手动创建代理类,代理类和目标类实现相同的接口。
interface Subject {
    void request();
}

class RealSubject implements Subject {
    @Override
    public void request() {
        System.out.println("RealSubject is handling request");
    }
}

class ProxySubject implements Subject {
    private RealSubject realSubject;

    public ProxySubject(RealSubject realSubject) {
        this.realSubject = realSubject;
    }

    @Override
    public void request() {
        System.out.println("Proxy is doing some pre - processing");
        realSubject.request();
        System.out.println("Proxy is doing some post - processing");
    }
}

public class StaticProxyExample {
    public static void main(String[] args) {
        RealSubject realSubject = new RealSubject();
        ProxySubject proxySubject = new ProxySubject(realSubject);
        proxySubject.request();
    }
}
  1. 动态代理 动态代理是在运行时动态生成代理类,Java 提供了 java.lang.reflect.Proxy 类和 InvocationHandler 接口来实现动态代理。
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

interface Subject {
    void request();
}

class RealSubject implements Subject {
    @Override
    public void request() {
        System.out.println("RealSubject is handling request");
    }
}

class DynamicProxyHandler implements InvocationHandler {
    private Object target;

    public DynamicProxyHandler(Object target) {
        this.target = target;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("Dynamic proxy is doing some pre - processing");
        Object result = method.invoke(target, args);
        System.out.println("Dynamic proxy is doing some post - processing");
        return result;
    }
}

public class DynamicProxyExample {
    public static void main(String[] args) {
        RealSubject realSubject = new RealSubject();
        DynamicProxyHandler handler = new DynamicProxyHandler(realSubject);
        Subject proxy = (Subject) Proxy.newProxyInstance(
                realSubject.getClass().getClassLoader(),
                realSubject.getClass().getInterfaces(),
                handler);
        proxy.request();
    }
}

适配器模式

  1. 概念 适配器模式将一个类的接口转换成客户希望的另一个接口,使得原本由于接口不兼容而不能一起工作的类可以一起工作。
  2. 类适配器 类适配器通过继承现有类并实现目标接口来实现。
class Adaptee {
    public void specificRequest() {
        System.out.println("Adaptee is handling specific request");
    }
}

interface Target {
    void request();
}

class ClassAdapter extends Adaptee implements Target {
    @Override
    public void request() {
        specificRequest();
    }
}

public class ClassAdapterExample {
    public static void main(String[] args) {
        Target target = new ClassAdapter();
        target.request();
    }
}
  1. 对象适配器 对象适配器通过组合现有类并实现目标接口来实现。
class Adaptee {
    public void specificRequest() {
        System.out.println("Adaptee is handling specific request");
    }
}

interface Target {
    void request();
}

class ObjectAdapter implements Target {
    private Adaptee adaptee;

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

    @Override
    public void request() {
        adaptee.specificRequest();
    }
}

public class ObjectAdapterExample {
    public static void main(String[] args) {
        Adaptee adaptee = new Adaptee();
        Target target = new ObjectAdapter(adaptee);
        target.request();
    }
}

行为型模式

策略模式

  1. 概念 策略模式定义了一系列算法,将每个算法封装起来,并使它们可以相互替换。策略模式使得算法的变化不会影响到使用算法的客户。
  2. 实现
interface Strategy {
    void execute();
}

class ConcreteStrategyA implements Strategy {
    @Override
    public void execute() {
        System.out.println("Executing ConcreteStrategyA");
    }
}

class ConcreteStrategyB implements Strategy {
    @Override
    public void execute() {
        System.out.println("Executing ConcreteStrategyB");
    }
}

class Context {
    private Strategy strategy;

    public Context(Strategy strategy) {
        this.strategy = strategy;
    }

    public void executeStrategy() {
        strategy.execute();
    }
}

public class StrategyExample {
    public static void main(String[] args) {
        Strategy strategyA = new ConcreteStrategyA();
        Context contextA = new Context(strategyA);
        contextA.executeStrategy();

        Strategy strategyB = new ConcreteStrategyB();
        Context contextB = new Context(strategyB);
        contextB.executeStrategy();
    }
}

观察者模式

  1. 概念 观察者模式定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象。当主题对象的状态发生变化时,会通知所有观察者对象,使它们能够自动更新。
  2. 实现
import java.util.ArrayList;
import java.util.List;

interface Observer {
    void update();
}

interface Subject {
    void attach(Observer observer);
    void detach(Observer observer);
    void notifyObservers();
}

class ConcreteSubject implements Subject {
    private List<Observer> observers = new ArrayList<>();
    private int state;

    public int getState() {
        return state;
    }

    public void setState(int state) {
        this.state = state;
        notifyObservers();
    }

    @Override
    public void attach(Observer observer) {
        observers.add(observer);
    }

    @Override
    public void detach(Observer observer) {
        observers.remove(observer);
    }

    @Override
    public void notifyObservers() {
        for (Observer observer : observers) {
            observer.update();
        }
    }
}

class ConcreteObserver implements Observer {
    private ConcreteSubject subject;

    public ConcreteObserver(ConcreteSubject subject) {
        this.subject = subject;
    }

    @Override
    public void update() {
        System.out.println("Observer updated, new state: " + subject.getState());
    }
}

public class ObserverExample {
    public static void main(String[] args) {
        ConcreteSubject subject = new ConcreteSubject();
        ConcreteObserver observer1 = new ConcreteObserver(subject);
        ConcreteObserver observer2 = new ConcreteObserver(subject);

        subject.attach(observer1);
        subject.attach(observer2);

        subject.setState(10);
    }
}

通过深入理解面向对象思想以及各种设计模式,Java 开发者能够编写出更加灵活、可维护和可扩展的代码,在实际项目开发中提升效率和质量。无论是小型项目还是大型企业级应用,这些知识都能发挥重要作用,帮助开发者更好地应对各种复杂的业务需求。