面向对象编程(Object-Oriented Programming, OOP)是一种编程范式,它使用“对象”来设计应用程序和软件。OOP的主要特性有三个:封装(Encapsulation)、继承(Inheritance)和多态(Polymorphism)。
面向对象------封装
封装是指将数据(属性)和操作数据的方法(函数)捆绑在一起,形成一个独立的实体,即对象。这样做可以隐藏对象的内部实现细节,只通过对象提供的接口与外界交互。
简单例子:
public 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 void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
// 描述信息的方法
public void introduce() {
System.out.println("My name is " + name + " and I am " + age + " years old.");
}
}
// 使用示例
public class Main {
public static void main(String[] args) {
Person person = new Person("Alice", 25);
person.introduce(); // 输出:My name is Alice and I am 25 years old.
}
}
封装在设计模式中的体现:
1. 策略模式(Strategy Pattern):策略模式允许一个类的实例根据其内部策略改变其行为,策略对象被封装在独立的类中,客户端代码只需要与策略接口交互,而不关心具体的策略实现,这体现了良好的封装性。
// 定义策略接口
public interface PaymentStrategy {
void pay();
}
// 具体的支付策略类1
public class PayPal implements PaymentStrategy {
@Override
public void pay() {
System.out.println("Paying via PayPal...");
}
}
// 具体的支付策略类2
public class WeChatPay implements PaymentStrategy {
@Override
public void pay() {
System.out.println("Paying via WeChat Pay...");
}
}
// 使用PaymentContext类来决定使用哪种支付策略
public class PaymentContext {
private PaymentStrategy strategy;
public PaymentContext(PaymentStrategy strategy) {
this.strategy = strategy;
}
public void setPaymentStrategy(PaymentStrategy strategy) {
this.strategy = strategy;
}
public void pay(double amount) {
System.out.println("Payment amount: " + amount);
strategy.pay();
}
}
// 客户端代码
public class Client {
public static void main(String[] args) {
PaymentContext context = new PaymentContext(new PayPal()); // 使用PayPal作为支付策略
context.pay(100); // 输出:Payment amount: 100.0, Paying via PayPal...
context.setPaymentStrategy(new WeChatPay()); // 更改支付策略为WeChatPay
context.pay(200); // 输出:Payment amount: 200.0, Paying via WeChat Pay...
}
}
2. 访问者模式(Visitor Pattern):访问者模式将算法与其所操作的数据结构解耦。这种模式中,数据结构(对象)与访问它的算法(对象)分离,算法被封装在访问者类中,这体现了良好的封装性。
// 定义访问者接口
public interface Visitor {
void visit(ConcreteElement1 element);
void visit(ConcreteElement2 element);
}
// 定义元素接口
public interface Element {
void accept(Visitor visitor);
}
// 具体元素类1
public class ConcreteElement1 implements Element {
@Override
public void accept(Visitor visitor) {
visitor.visit(this);
}
}
// 具体元素类2
public class ConcreteElement2 implements Element {
@Override
public void accept(Visitor visitor) {
visitor.visit(this);
}
}
// 具体访问者类1
public class ConcreteVisitor1 implements Visitor {
@Override
public void visit(ConcreteElement1 element) {
System.out.println("Visiting ConcreteElement1 with ConcreteVisitor1...");
}
@Override
public void visit(ConcreteElement2 element) {
System.out.println("Visiting ConcreteElement2 with ConcreteVisitor1...");
}
}
// 具体访问者类2
public class ConcreteVisitor2 implements Visitor {
@Override
public void visit(ConcreteElement1 element) {
System.out.println("Visiting ConcreteElement1 with ConcreteVisitor2...");
}
@Override
public void visit(ConcreteElement2 element) {
System.out.println("Visiting ConcreteElement2 with ConcreteVisitor2...");
}
}
// 客户端代码
public class Client {
public static void main(String[] args) {
ConcreteElement1 element1 = new ConcreteElement1(); // 创建具体元素1的实例
ConcreteElement2 element2 = new ConcreteElement2(); // 创建具体元素2的实例
Visitor visitor1 = new ConcreteVisitor1(); // 创建具体访问者1的实例,用于访问元素1和元素2
Visitor visitor2 = new ConcreteVisitor2(); // 创建具体访问者2的实例,用于访问元素1和元素2
element1.accept(visitor1); // 输出:Visiting ConcreteElement1 with ConcreteVisitor1...
element2.accept(visitor2); // 输出:Visiting ConcreteElement2 with ConcreteVisitor2...
element1.accept(visitor2); // 输出:Visiting ConcreteElement1 with ConcreteVisitor2...
element2.accept(visitor1); // 输出:Visiting ConcreteElement2 with ConcreteVisitor1...
}
}
面向对象------继承
继承是面向对象编程中的一个重要概念,它允许一个类(子类)继承另一个类(父类)的属性和方法。子类可以重用父类的代码,并且可以增加新的属性和方法,或者重写父类的方法。
简单例子:
// 父类 Animal
public class Animal {
public void eat() {
System.out.println("The animal eats.");
}
}
// 子类 Dog 继承自 Animal
public class Dog extends Animal {
// 子类特有的方法
public void bark() {
System.out.println("The dog barks.");
}
// 重写父类的方法
@Override
public void eat() {
System.out.println("The dog eats dog food.");
}
}
// 使用示例
public class Main {
public static void main(String[] args) {
Dog dog = new Dog();
dog.eat(); // 输出:The dog eats dog food.
dog.bark(); // 输出:The dog barks.
}
}
封装在设计模式中的体现:
1. 装饰器模式(Decorator Pattern):装饰器模式动态地给一个对象增加一些额外的职责,就像增加一些装饰品。这种模式中,通过继承,子类可以添加新的行为或功能,或者修改现有父类的行为,这体现了继承的特性。
// 定义组件接口
public interface Component {
void operation();
}
// 定义具体组件类
public class ConcreteComponent implements Component {
@Override
public void operation() {
System.out.println("Executing operation in ConcreteComponent...");
}
}
// 定义装饰器抽象类
public abstract class Decorator implements Component {
protected Component component;
public Decorator(Component component) {
this.component = component;
}
@Override
public void operation() {
component.operation(); // 先执行原始操作
decorate(); // 再执行附加操作
}
protected abstract void decorate(); // 定义一个抽象方法,用于实现附加操作
}
// 具体装饰器类1
public class ConcreteDecorator1 extends Decorator {
public ConcreteDecorator1(Component component) {
super(component);
}
@Override
protected void decorate() {
System.out.println("Applying decoration 1...");
}
}
// 具体装饰器类2
public class ConcreteDecorator2 extends Decorator {
public ConcreteDecorator2(Component component) {
super(component);
}
@Override
protected void decorate() {
System.out.println("Applying decoration 2...");
}
}
// 客户端代码
public class Client {
public static void main(String[] args) {
Component component = new ConcreteComponent(); // 创建具体组件的实例
Decorator decorator1 = new ConcreteDecorator1(component); // 创建装饰器1的实例,并将其附加到组件上
Decorator decorator2 = new ConcreteDecorator2(decorator1); // 创建装饰器2的实例,并将其附加到装饰器1上(和组件上)
decorator2.operation(); // 输出:Executing operation in ConcreteComponent...,Applying decoration 1...,Applying decoration 2...
}
}
2. 模板方法模式(Template Method Pattern):模板方法模式定义了一个操作中的算法骨架,将某些步骤延迟到子类中实现。这种模式体现了继承中的多态性,因为子类可以通过重写方法来定制算法的某些步骤。
面向对象------多态
多态是指允许使用父类引用指向子类对象,并且在运行时根据实际的对象类型来决定调用哪个方法。Java 中实现多态的方式主要有方法重载(Overloading)和方法重写(Overriding)
简单例子:
// 父类 Shape
public class Shape {
public void draw() {
System.out.println("Drawing a shape...");
}
}
// 子类 Circle 继承自 Shape
public class Circle extends Shape {
@Override
public void draw() {
System.out.println("Drawing a circle...");
}
}
// 子类 Rectangle 继承自 Shape
public class Rectangle extends Shape {
@Override
public void draw() {
System.out.println("Drawing a rectangle...");
}
}
// 使用示例
public class Main {
public static void main(String[] args) {
// 使用父类引用指向子类对象
Shape shape1 = new Circle();
Shape shape2 = new Rectangle();
// 调用 draw 方法,实际执行的是子类的方法
shape1.draw(); // 输出:Drawing a circle...
shape2.draw(); // 输出:Drawing a rectangle...
}
}
封装在设计模式中的体现:
1. 代理模式(Proxy Pattern):代理模式为其他对象提供一种代理以控制对这个对象的访问。这种模式中,客户端对代理和真实对象的引用可以替换,这体现了多态的特性。
// 定义目标接口
public interface Target {
void request();
}
// 定义具体目标类
public class ConcreteTarget implements Target {
@Override
public void request() {
System.out.println("Executing request in ConcreteTarget...");
}
}
// 定义代理接口,继承目标接口
public interface Proxy extends Target {
void access(); // 定义一个附加方法,用于在访问目标对象前后执行操作
}
// 定义具体代理类,实现代理接口,持有对目标对象的引用,并调用目标对象的方法
public class ConcreteProxy implements Proxy {
private Target target;
public ConcreteProxy(Target target) {
this.target = target;
}
@Override
public void request() {
access(); // 在访问目标对象前执行附加操作
target.request(); // 调用目标对象的方法
access(); // 在访问目标对象后执行附加操作
}
@Override
public void access() {
System.out.println("Accessing target object...");
}
}
// 客户端代码
public class Client {
public static void main(String[] args) {
Target target = new ConcreteTarget(); // 创建具体目标对象的实例
Proxy proxy = new ConcreteProxy(target); // 创建具体代理对象的实例,并将其附加到目标对象上
proxy.request(); // 输出:Accessing target object...,Executing request in ConcreteTarget...,Accessing target object...
}
}
2. 观察者模式(Observer Pattern):观察者模式定义了对象之间的一对多依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都会得到通知并被自动更新。这种模式的实现中,观察者和被观察者之间是多对多的关系,体现了多态的特性。
// 定义主题接口,声明了添加和删除观察者以及通知观察者的方法
public interface Subject {
void addObserver(Observer observer);
void removeObserver(Observer observer);
void notifyObservers();
}
// 定义具体主题类,实现了主题接口,维护了一个观察者列表,并在状态改变时通知所有观察者
public class ConcreteSubject implements Subject {
private List<Observer> observers = new ArrayList<>();
private int state;
public ConcreteSubject(int state) {
this.state = state;
}
@Override
public void addObserver(Observer observer) {
observers.add(observer);
}
@Override
public void removeObserver(Observer observer) {
observers.remove(observer);
}
@Override
public void notifyObservers() {
for (Observer observer : observers) {
observer.update(state);
}
}
public void setState(int state) {
this.state = state;
notifyObservers(); // 在状态改变时通知所有观察者
}
}
// 定义观察者接口,声明了更新方法,用于接收主题的通知
public interface Observer {
void update(int state);
}
// 定义具体观察者类1,实现了观察者接口,并在更新方法中处理主题的通知
public class ConcreteObserver1 implements Observer {
private String name;
public ConcreteObserver1(String name) {
this.name = name;
}
@Override
public void update(int state) {
System.out.println(name + " received update: " + state);
}
}
// 定义具体观察者类2,实现了观察者接口,并在更新方法中处理主题的通知
public class ConcreteObserver2 implements Observer {
private String name;
public ConcreteObserver2(String name) {
this.name = name;
}
@Override
public void update(int state) {
System.out.println(name + " received update: " + state);
}
}
// 客户端代码
public class Client {
public static void main(String[] args) {
ConcreteSubject subject = new ConcreteSubject(0); // 创建具体主题对象的实例,并设置初始状态为0
Observer observer1 = new ConcreteObserver1("Observer 1"); // 创建具体观察者1的实例并将其添加到主题对象上作为观察者
Observer observer2 = new ConcreteObserver2("Observer 2"); // 创建具体观察者2的实例并将其添加到主题对象上作为观察者
subject.addObserver(observer1); // 将观察者1添加到主题对象上作为观察者,并接收主题的通知更新自己的状态信息
subject.addObserver(observer2); // 将观察者2添加到主题对象上作为观察者,并接收主题的通知更新自己的状态信息
subject.setState(1); // 设置主题对象的新的状态为1,并通知所有观察者更新自己的状态信息,输出:Observer 1 received update: 1,Observer 2 received update: 1,Observer 1 received update: 1,Observer 2 received update: 1(因为每个观察者都添加了两次))这里可能存在重复输出的问题,在实际使用中需要根据具体情况进行处理)