Skip to content

什么是面向对象

面向对象编程(Object-Oriented Programming, 简称OOP)是一种编程范式, Rust 是一个00后的年轻语言, 它还没被设计出来时, 就已经有很多的编程范式了, 什么过程式编程, 函数式编程, 当然也包括面向对象编程, 所以作者在设计 Rust 的时候, 不可避免的会参考这些已经存在的编程范式

面向对象是一个比较宽泛的概念, 在很多资料中会认为只有像Java那种(class/extends/interface/implements)才叫面向对象, 但其实我觉得只要符合面向对象编程特点的编程方式, 都可以称之为面向对象编程

面向对象编程的特点: 封装 继承(复用) 多态

对象包含数据和行为

面向对象的程序是由对象组成的, 一个对象包含数据和操作这些数据的过程, 这些过程通常被称为方法或操作

rust
struct Cat {
  // 成员属性
  name: String,
  age: u32,
}

impl Cat {
  // 实例化
  fn new(name: String, age: u32) -> Self {
    Self { name, age }
  }

  // 成员方法
  fn catch_mouse(&self) {
    println!("抓老鼠");
  }
}

封装: 隐藏实现细节

rust
struct Cat {
  name: String,
  age: u32,
}

impl Cat {
  fn new(name: String, age: u32) -> Self {
    Self { name, age }
  }
  fn catch_mouse(&self) {
    println!("抓老鼠");
  }
}

fn main() {
  let c = Cat::new(String::from("tom"), 10);

  // 不需要管这个方法如何实现的, 只需要知道这个方法的作用即可
  c.catch_mouse();
}

继承: 代码复用和共享

rust
trait Animal {
    fn eat(&self) {
        println!("动物需要吃东西");
    }
    fn breathe(&self) {
        println!("动物需要呼吸氧气");
    }
}

struct Cat {
  name: String,
  age: u32,
}

impl Cat {
  fn new(name: String, age: u32) -> Self {
    Self { name, age }
  }
  fn catch_mouse(&self) {
    println!("抓老鼠");
  }
}

// 可以看做继承了 Animal
impl Animal for Cat {}

fn main() {
    let c = Cat::new(String::from("tom"), 10);
    c.catch_mouse();
    c.eat();
    c.breathe();
}

多态: 代码的灵活和扩展性

rust
trait Animal {
    fn eat(&self) {
        println!("动物需要吃东西");
    }
}

struct Cat {}
impl Animal for Cat {
    fn eat(&self) {
        println!("猫吃鱼");
    }
}

struct Dog {}
impl Animal for Dog {
    fn eat(&self) {
        println!("狗吃骨头");
    }
}


// 不管是猫吃东西(Cat eat)还是狗吃东西(Dog eat)
// 都可以看做是动物在吃东西(Animal eat)
// 对比代码, 不管传入的a具体是什么, 只要 a 实现了 Animal 这个 trait 就行
fn animal_eat_something<T: Animal>(a: T) {
    a.eat();
}

fn main() {
    let c = Cat{};
    let d = Dog{};

    animal_eat_something(c);
    animal_eat_something(d);
}
rust
struct Cat {}
struct Dog {}

fn cats_eat_fish(c: Cat) {
    println!("猫吃鱼");
}
fn dogs_eat_bones(d: Dog) {
    println!("狗吃骨头:");
}

// 如果有100种动物就要定义100个不同的方法

fn main() {
    let c = Cat{};
    let d = Dog{};

    cats_eat_fish(c);
    dogs_eat_bones(d);
}

面向对象: 适配器模式的实现

在Rust程序设计语言这本书中, 有一个状态模式的例子 那我就写一个更易于理解的适配器模式的例子吧

rust
use std::collections::HashMap;

////////////////////////////
/////    可缓存的特性  /////
////////////////////////////
trait Cacheable {
    fn get_by_key(&self, key:String);
    fn set_by_key(&mut self, key:String, value: String);
    fn clear(&mut self); // 为了易读和方便就不使用 Refcell 了, 直接传入可变引用算了
}

////////////////////////////
///// 文件缓存具体实现 /////
////////////////////////////
struct FileCache {
    file_path: String, // 缓存保存到哪个文件中
}
impl FileCache {
    fn new(file_path: String) -> FileCache {
        FileCache { file_path }
    }
    fn read_cache_from_file(&self, key:String) {
        println!("从文件中读取缓存, {}", key);
    }
    fn write_cache_to_file(&self, key:String, value: String) {
        println!("将要缓存的数据写入文件中, {}, {}", key, value);
    }
    fn delete_cache_file(&self) {
        println!("删除缓存文件, {}", self.file_path);
    }
}

////////////////////////////
///// 文件缓存适配器 ///////
////////////////////////////
struct FileCacheAdapter {
    driver: FileCache
}
impl FileCacheAdapter {
    fn new(file_path: String) -> FileCacheAdapter {
        FileCacheAdapter {
            driver: FileCache::new(file_path)
        }
    }
}
impl Cacheable for FileCacheAdapter {
    fn get_by_key(&self, key:String) {
        self.driver.read_cache_from_file(key);
    }
    fn set_by_key(&mut self, key:String, value: String) {
        self.driver.write_cache_to_file(key, value);
    }
    fn clear(&mut self) {
        self.driver.delete_cache_file();
    }
}

// 内存缓存具体实现: 可以没有具体实现, 直接将功能直接放到适配器中,
// 因为在适配器模式中, 具体实现一般都是私有的, 适配器才是公开的API
// struct MemoryCache { }

///////////////////////////
///// 内存缓存适配器 //////
///////////////////////////
struct MemoryCacheAdapter {
    cache_map: HashMap<String, String>
}
impl MemoryCacheAdapter {
    fn new() -> MemoryCacheAdapter {
        MemoryCacheAdapter {
            cache_map: HashMap::new(),
        }
    }
}
impl Cacheable for MemoryCacheAdapter {
    fn get_by_key(&self, key: String) {
        let val = self.cache_map.get(&key);
        println!("从内存中读取缓存: {:?}", val);
    }
    fn set_by_key(&mut self, key:String, value: String) {
        self.cache_map.insert(key, value);
        println!("将缓存放入内存中: {:?}", self.cache_map);
    }
    fn clear(&mut self) {
        self.cache_map.clear();
        println!("清除内存中的缓存: {:?}", self.cache_map);
    }
}

// 如果还需要扩展更多缓存方式
// struct MysqlCache { /* 具体实现 */ }
// struct MysqlCacheAdapter { /* 适配器 */ }
// impl Cacheable for MysqlCacheAdapter { /* 为适配器实现接口 */ }

// struct PgsqlCache { /* 具体实现 */ }
// struct PgsqlCacheAdapter { /* 适配器 */ }
// impl Cacheable for PgsqlCacheAdapter { /* 为适配器实现接口 */ }

fn main() {
    let mut cache_adapter = MemoryCacheAdapter::new();
    // let mut cache_adapter = FileCacheAdapter::new("./1.cache.json".to_string());

    cache_adapter.get_by_key("key1".to_string());
    cache_adapter.set_by_key("key1".to_string(), "value1".to_string());
    cache_adapter.get_by_key("key1".to_string());
    cache_adapter.clear();
}

Released under the MIT License.