以下内容均来自抖音号【it楠老师教java】的设计模式课程。
子类对象(objectofsubtype/derivedclass)能够替换程序(program)中父类对象(objectofbase/parentclass)出现的任何地方,并且保证原来程序的逻辑行为(behavior)不变及正确性不被破坏。
// 基类:鸟类public class Bird {public void fly () {System . out . println ( "I can fly" );} }// 子类:企鹅类public class Penguin extends Bird {// 企鹅不能飞,所以覆盖了基类的 fly 方法,但这违反了里氏替换原则public void fly () {throw new UnsupportedOperationException ( "Penguins can't fly" );}}
// 飞行行为接口public interface Flyable {void fly ();}// 基类:鸟类public class Bird {}// 子类:能飞的鸟类public class FlyingBird extends Bird implements Flyable {@Overridepublic void fly () {System . out . println ( "I can fly" );}}// 子类:企鹅类,不实现 Flyable 接口public class Penguin extends Bird {}
这里就该明确那些方法是通用的,哪些方法是部分能用的。
比如通用的方法可以放到class bird里。
public void say(){ System.out.println("我属于鸟科")}
public void say(){ System.out.println("我又一双翅膀,尽管不能飞")}
不同的用的方法,可以放到接口里比如有的鸟很小 有的鸟很大
interface BigBird{ double height()}
interface SmallBird{ double height()}
上述可能不太准确,但是核心思想就是抽取公共的方法到类里,抽取特殊的方法到接口里。
再举个例 比如
class door{
//核心方法 只要是门 不管你啥样的 你肯定又面积吧,有价格吧
int price();
int area();
}
但是有的门市防火门 有的是防盗门, 有的是....
interface FangHuo{ void canFangHuo()};
interface FangDao{ void canFangDao()};
我们再来看一个基于数据库操作的案例。假设我们正在开发一个支持多种数据库的程序,包括MySQL、PostgreSQL和SQLite。我们可以使用里氏替换原则来设计合适的类结构,确保代码的可维护性和扩展性。 首先,我们定义一个抽象的Database 基类,它包含一些通用的数据库操作方法, 如 connect() 、disconnect() 和 executeQuery() 。这些方法的具体实现将在 子类中完成。
public abstract class Database {public abstract void connect ();public abstract void disconnect ();public abstract void executeQuery ( String query );}
然后,为每种数据库类型创建一个子类,继承自 Database 基类。这些子类需要实现基类中定义的抽象方法,并可以添加特定于各自数据库的方法。
这里新手要思考下 为什么用abstract class 怎么不用class 怎么不用interface
不用class,因为我这里还没有具体到那类数据源,其实可以定义个jdbcDatabase ,定义属性driver,url,user ,password。就是更一部的抽取
不用interface 因为connect close 和query是所有数据源都有操作!!!
public class MySQLDatabase extends Database {@Overridepublic void connect () {// 实现 MySQL 的连接逻辑}@Overridepublic void disconnect () {// 实现 MySQL 的断开连接逻辑}@Overridepublic void executeQuery ( String query ) {// 实现 MySQL 的查询逻辑}// 其他针对 MySQL 的特定方法}public class PostgreSQLDatabase extends Database {// 类似地,为 PostgreSQL 实现相应的方法}public class SQLiteDatabase extends Database {// 类似地,为 SQLite 实现相应的方法}
这样设计的好处是,我们可以在不同的数据库类型之间灵活切换,而不需要修改大量代码。只要这些子类遵循里氏替换原则,我们就可以放心地使用基类的引用来操作不同类型的数据库。例如:
public class DatabaseClient {private Database database ;public DatabaseClient ( Database database ) {this . database = database ;}public void performDatabaseOperations () {database . connect ();database . executeQuery ( "SELECT * FROM users" );database . disconnect ();}}public class Main {public static void main ( String [] args ) {// 使用 MySQL 数据库DatabaseClient client1 = new DatabaseClient ( new MySQLDatabase ());client1 . performDatabaseOperations ();// 切换到 PostgreSQL 数据库DatabaseClient client2 = new DatabaseClient ( new PostgreSQLDatabase ());client2 . performDatabaseOperations ();// 切换到 SQLite 数据库DatabaseClient client3 = new DatabaseClient ( new SQLiteDatabase ());client3 . performDatabaseOperations ();}}
好了,我们稍微总结一下。虽然从定义描述和代码实现上来看,多态和里式替换有点类似,但它们关注的角度是不一样的。多态是面向对象编程的一大特性,也是面向对象编程语言的一种语法。它是一种代码实现的思路。而里式替换是一种设计原则,是用来指导继承关系中子类该如何设计的,子类的设计要保证在替换父类的时候,不改变原有程序的逻辑以及不破坏原有程序的正确性。
当子类覆盖或修改基类的方法时,可能导致子类无法替换基类的实例而不引起问题。这违反了LSP,会导致代码变得脆弱和不易维护。
public class Bird {public void fly () {System . out . println ( "I can fly" );}}public class Penguin extends Bird {@Overridepublic void fly () {throw new UnsupportedOperationException ( "Penguins can't fly" );}}
当子类违反了基类中定义的约束条件(如输入、输出或异常等),也会违反LSP。
public class Stack {private int top ;private int [] elements ;public Stack ( int size ) {elements = new int [ size ];top = - 1 ;}public void push ( int value ) {if ( top >= elements . length - 1 ) {throw new IllegalStateException ( "Stack is full" );} elements [ ++ top ] = value ;}public int pop () {if ( top < 0 ) {throw new IllegalStateException ( "Stack is empty" );}return elements [ top -- ];}}// 正数的栈public class NonNegativeStack extends Stack {public NonNegativeStack ( int size ) {super ( size );}@Overridepublic void push ( int value ) {if ( value < 0 ) {throw new IllegalArgumentException ( "Only non-negative values are allowed" );}super . push ( value );}}// 正确的写法public class NonNegativeStack extends Stack {public NonNegativeStack ( int size ) {super ( size );}public void pushNonNegative ( int value ) {if ( value < 0 ) {throw new IllegalArgumentException ( "Only non-negative values are allowed" );}super . push ( value );}}
这里感觉给的资料有问题。。。等我看完视频在说