渭南市工程建設(shè)項(xiàng)目審批平臺(tái)免費(fèi)的關(guān)鍵詞優(yōu)化軟件
以下內(nèi)容均來(lái)自抖音號(hào)【it楠老師教java】的設(shè)計(jì)模式課程。
1、原理概述
子類(lèi)對(duì)象(objectofsubtype/derivedclass)能夠替換程序(program)中父類(lèi)對(duì)象(objectofbase/parentclass)出現(xiàn)的任何地方,并且保證原來(lái)程序的邏輯行為(behavior)不變及正確性不被破壞。
2、簡(jiǎn)單的示例1
// 基類(lèi):鳥(niǎo)類(lèi)public class Bird {public void fly () {System . out . println ( "I can fly" );} }// 子類(lèi):企鵝類(lèi)public class Penguin extends Bird {// 企鵝不能飛,所以覆蓋了基類(lèi)的 fly 方法,但這違反了里氏替換原則public void fly () {throw new UnsupportedOperationException ( "Penguins can't fly" );}}
// 飛行行為接口public interface Flyable {void fly ();}// 基類(lèi):鳥(niǎo)類(lèi)public class Bird {}// 子類(lèi):能飛的鳥(niǎo)類(lèi)public class FlyingBird extends Bird implements Flyable {@Overridepublic void fly () {System . out . println ( "I can fly" );}}// 子類(lèi):企鵝類(lèi),不實(shí)現(xiàn) Flyable 接口public class Penguin extends Bird {}
這里就該明確那些方法是通用的,哪些方法是部分能用的。
比如通用的方法可以放到class bird里。
public void say(){ System.out.println("我屬于鳥(niǎo)科")}
public void say(){ System.out.println("我又一雙翅膀,盡管不能飛")}
不同的用的方法,可以放到接口里比如有的鳥(niǎo)很小 有的鳥(niǎo)很大
interface? BigBird{ double height()}
interface? SmallBird{ double height()}
上述可能不太準(zhǔn)確,但是核心思想就是抽取公共的方法到類(lèi)里,抽取特殊的方法到接口里。
再舉個(gè)例 比如
class? door{
//核心方法 只要是門(mén) 不管你啥樣的 你肯定又面積吧,有價(jià)格吧
int price();
int area();
}
但是有的門(mén)市防火門(mén) 有的是防盜門(mén), 有的是....
interface FangHuo{ void canFangHuo()};
interface FangDao{ void canFangDao()};
3、示例2
我們?cè)賮?lái)看一個(gè)基于數(shù)據(jù)庫(kù)操作的案例。假設(shè)我們正在開(kāi)發(fā)一個(gè)支持多種數(shù)據(jù)庫(kù)的程序,包括MySQL、PostgreSQL和SQLite。我們可以使用里氏替換原則來(lái)設(shè)計(jì)合適的類(lèi)結(jié)構(gòu),確保代碼的可維護(hù)性和擴(kuò)展性。 首先,我們定義一個(gè)抽象的Database 基類(lèi),它包含一些通用的數(shù)據(jù)庫(kù)操作方法, 如 connect() 、disconnect() 和 executeQuery() 。這些方法的具體實(shí)現(xiàn)將在 子類(lèi)中完成。
public abstract class Database {public abstract void connect ();public abstract void disconnect ();public abstract void executeQuery ( String query );}
然后,為每種數(shù)據(jù)庫(kù)類(lèi)型創(chuàng)建一個(gè)子類(lèi),繼承自 Database 基類(lèi)。這些子類(lèi)需要實(shí)現(xiàn)基類(lèi)中定義的抽象方法,并可以添加特定于各自數(shù)據(jù)庫(kù)的方法。
這里新手要思考下 為什么用abstract class 怎么不用class 怎么不用interface
不用class,因?yàn)槲疫@里還沒(méi)有具體到那類(lèi)數(shù)據(jù)源,其實(shí)可以定義個(gè)jdbcDatabase ,定義屬性driver,url,user ,password。就是更一部的抽取
不用interface 因?yàn)閏onnect close 和query是所有數(shù)據(jù)源都有操作!!!
public class MySQLDatabase extends Database {@Overridepublic void connect () {// 實(shí)現(xiàn) MySQL 的連接邏輯}@Overridepublic void disconnect () {// 實(shí)現(xiàn) MySQL 的斷開(kāi)連接邏輯}@Overridepublic void executeQuery ( String query ) {// 實(shí)現(xiàn) MySQL 的查詢(xún)邏輯}// 其他針對(duì) MySQL 的特定方法}public class PostgreSQLDatabase extends Database {// 類(lèi)似地,為 PostgreSQL 實(shí)現(xiàn)相應(yīng)的方法}public class SQLiteDatabase extends Database {// 類(lèi)似地,為 SQLite 實(shí)現(xiàn)相應(yīng)的方法}?
這樣設(shè)計(jì)的好處是,我們可以在不同的數(shù)據(jù)庫(kù)類(lèi)型之間靈活切換,而不需要修改大量代碼。只要這些子類(lèi)遵循里氏替換原則,我們就可以放心地使用基類(lèi)的引用來(lái)操作不同類(lèi)型的數(shù)據(jù)庫(kù)。例如:?
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 數(shù)據(jù)庫(kù)DatabaseClient client1 = new DatabaseClient ( new MySQLDatabase ());client1 . performDatabaseOperations ();// 切換到 PostgreSQL 數(shù)據(jù)庫(kù)DatabaseClient client2 = new DatabaseClient ( new PostgreSQLDatabase ());client2 . performDatabaseOperations ();// 切換到 SQLite 數(shù)據(jù)庫(kù)DatabaseClient client3 = new DatabaseClient ( new SQLiteDatabase ());client3 . performDatabaseOperations ();}}
好了,我們稍微總結(jié)一下。雖然從定義描述和代碼實(shí)現(xiàn)上來(lái)看,多態(tài)和里式替換有點(diǎn)類(lèi)似,但它們關(guān)注的角度是不一樣的。多態(tài)是面向?qū)ο缶幊痰囊淮筇匦?#xff0c;也是面向?qū)ο缶幊陶Z(yǔ)言的一種語(yǔ)法。它是一種代碼實(shí)現(xiàn)的思路。而里式替換是一種設(shè)計(jì)原則,是用來(lái)指導(dǎo)繼承關(guān)系中子類(lèi)該如何設(shè)計(jì)的,子類(lèi)的設(shè)計(jì)要保證在替換父類(lèi)的時(shí)候,不改變?cè)谐绦虻倪壿嬕约安黄茐脑谐绦虻恼_性。?
1.子類(lèi)覆蓋或修改了基類(lèi)的方法
當(dāng)子類(lèi)覆蓋或修改基類(lèi)的方法時(shí),可能導(dǎo)致子類(lèi)無(wú)法替換基類(lèi)的實(shí)例而不引起問(wèn)題。這違反了LSP,會(huì)導(dǎo)致代碼變得脆弱和不易維護(hù)。
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" );}}
?
2、子類(lèi)違反了基類(lèi)的約束條件
當(dāng)子類(lèi)違反了基類(lèi)中定義的約束條件(如輸入、輸出或異常等),也會(huì)違反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 -- ];}}// 正數(shù)的棧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 );}}// 正確的寫(xiě)法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 );}}
這里感覺(jué)給的資料有問(wèn)題。。。等我看完視頻在說(shuō)?