花桥做网站,免费 wordpress企业主题,建筑工地新型材料模板,什么叫域名访问网站以下内容均来自抖音号【it楠老师教java】的设计模式课程。
1、原理概述
子类对象#xff08;objectofsubtype/derivedclass#xff09;能够替换程序#xff08;program#xff09;中父类对象#xff08;objectofbase/parentclass#xff09;出现的任何地方#xff0c…以下内容均来自抖音号【it楠老师教java】的设计模式课程。
1、原理概述
子类对象objectofsubtype/derivedclass能够替换程序program中父类对象objectofbase/parentclass出现的任何地方并且保证原来程序的逻辑行为behavior不变及正确性不被破坏。
2、简单的示例1 // 基类鸟类 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 cant fly ); } } 为了遵循LSP我们可以重新设计类结构将能飞的行为抽象到一个接口中让需要飞行能力的鸟类实现这个接口 // 飞行行为接口 public interface Flyable { void fly (); } // 基类鸟类 public class Bird { } // 子类能飞的鸟类 public class FlyingBird extends Bird implements Flyable { Override public 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()};
3、示例2
我们再来看一个基于数据库操作的案例。假设我们正在开发一个支持多种数据库的程序包括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 定义属性driverurluser ,password。就是更一部的抽取
不用interface 因为connect close 和query是所有数据源都有操作 public class MySQLDatabase extends Database { Override public void connect () { // 实现 MySQL 的连接逻辑 } Override public void disconnect () { // 实现 MySQL 的断开连接逻辑 } Override public 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 (); } } 好了我们稍微总结一下。虽然从定义描述和代码实现上来看多态和里式替换有点类似但它们关注的角度是不一样的。多态是面向对象编程的一大特性也是面向对象编程语言的一种语法。它是一种代码实现的思路。而里式替换是一种设计原则是用来指导继承关系中子类该如何设计的子类的设计要保证在替换父类的时候不改变原有程序的逻辑以及不破坏原有程序的正确性。 2 、哪些代码明显违背了 LSP 1.子类覆盖或修改了基类的方法
当子类覆盖或修改基类的方法时可能导致子类无法替换基类的实例而不引起问题。这违反了LSP会导致代码变得脆弱和不易维护。 public class Bird { public void fly () { System . out . println ( I can fly ); } } public class Penguin extends Bird { Override public void fly () { throw new UnsupportedOperationException ( Penguins cant fly ); } } 在这个例子中 Penguin 类覆盖了 Bird 类的 fly() 方法抛出了一个异常。这违反了LSP因为现在 Penguin 实例无法替换 Bird 实例而不引发问题。 2、子类违反了基类的约束条件
当子类违反了基类中定义的约束条件如输入、输出或异常等也会违反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 ); } Override public 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 ); } } 这里感觉给的资料有问题。。。等我看完视频在说