李氏代换是软件设计的一个原则,又名依赖倒转原则或依赖倒置原则,其衍生原则有接口分离原则等。该原则由Barbara Liskov于1988年提出。java
该原则指出,程序中高级别的元素应当独立于继承于它的低级别的元素独立存在,而程序中低级别的元素的设计和运行应当依赖于(继承)高级别元素的存在。换句话说,即高级的类、模块或接口应当不知道低级的类、模块或接口的存在,而低级的类、模块或接口的设计、实现以及运行应当继承高级的类、模块或接口,从而实现了“强内聚、低耦合”的软件设计要求。由此原则,能够衍生出如下一些规则(推论):python
规则2和3即为接口分离原则。编程
前不久金庸大侠和斯坦李大英雄都不幸逝世了,这两位大师的笔下叙述了不少的英雄形象(Hero)的故事,这个例子就与如何对小说影视等做品中出现的英雄人物编程有关。这些英雄人物各有不一样的故事(IStory)、不一样的超能力(IAbility),有的还有会飞(IFly)这种行为。能够设定为有超能力的英雄必定有故事,即用IAbility继承IStory。会飞的英雄必定有故事、而且有超能力,因此能够继承上述两个接口。设计模式
这些英雄形象通常在中国叫做武侠(Wuxia),而在美国叫作超人(SuperHero),所以能够将Wuxia和SuperHero根据李氏代换原则设置为Hero的子类,这些类应当实现IAbility接口。有的武侠会飞(FlyingWuxia),所以会飞的武侠能够继承武侠并扩展“会飞”的特性,而FlyingWuxia的实体在运行中也能够用于彻底替代武侠类。相似地能够建立FlyingSuperHero类。这些会飞的武侠或者超人应当去实现IFly这一接口。安全
在程序设计中,接口名通常以大写字母“I”开头,其Java实现以下:app
public interface IStory{ public void showStory(String whatHappened); } public interface IAbility extends IStory { public void showAbility(String whatAbility); } public interface IFly extends IAbility, IStory{ public void take_off(String tool); public void fly(); public void landing(); }
Java中接口能够多继承,可是类不能够。Python是个更强调具体实现的语言,因为(原则上)全部的类都是可实例化、可多继承的对象,所以没有了接口这一说。可是咱们仍然可使用abc模块的ABCMeta、abstractmethod这两个子模块进行接口与抽象类(设计上)的实现。标注abstractmethod的目的仅仅是为了提醒后续的类进行实现(固然与Java不一样,python中对于这些接口或抽象类的“抽象方法”不做实现也不会影响运行)编程语言
from abc import ABCMeta, abstractmethod class IStory: __metaclass__ = ABCMeta @abstractmethod def showStory(person, whatHappened): print(person, " experienced ", whatHappened) class IAbility(IStory): __metaclass__ = ABCMeta @abstractmethod def showAbility(person, ability): print(person, "has ability", ability) class IFly(IAbility, IStory): __metaclass__ = ABCMeta @abstractmethod def take_off(thing): print(thing, "takes off!") @abstractmethod def fly(thing): print(thing, "flying!") @abstractmethod def landing(thing): print(thing, "landing!")
关于Hero这个类的实现,因为每一个英雄人物都有特定的姓名、性别等特性,但每一个英雄都有不一样的故事,所以咱们能够考虑设置英雄为一个抽象类并包含抽象方法“它的故事”。ide
“英雄”的Java实现:函数
public abstract class Hero implements IAbility { private String name; private char gender; private String nationality; private int age; public Hero(String name, char gender, String nationality) { this(name, gender, nationality, 20); } public Hero(String name, char gender, String nationality, int age) { this.name = name; this.gender = gender; this.nationality = nationality; this.age = age; } @Override public void showAbility(String whatAbility) { System.out.println(this + " has ability " + whatAbility); } @Override public String toString(){ return name + " " + gender + " " + age + " " + nationality; } @Override public abstract void showStory(String whatHappened); }
“英雄”的Python实现:工具
class Hero(IAbility): def __init__(self, name, gender, nationality, age=20): self.__name = name self.__gender = gender self.__nationality = nationality self.__age = age def __str__(self): return (self.__name + " " + self.__gender + " " + str(self.__age) + " comes from " + self.__nationality) @abstractmethod def showStory(self, whatHappened): print(self, " experienced ", whatHappened)
其余的“武侠”、“超人”等实现,继承“英雄”类并实现“超能力”接口便可,会飞的英雄人物须要实现“飞行”接口。这都比较简单,此处就直接上代码出招,不作赘述。
“武侠”类的Java实现:
public class Wuxia extends Hero{ public Wuxia(String name, char gender) { super(name, gender, "中国", 20); } public Wuxia(String name, char gender, int age) { super(name, gender, "中国", age); } @Override public String toString(){ return super.toString(); } @Override public void showStory(String whatHappened) { System.out.println(this + " experienced " + whatHappened); } }
“武侠”类的Python实现:
class Wuxia(Hero): def __init__(self, name, gender, age=20): Hero.__init__(self, name, gender, "中国", age)
“飞行武侠”类的Java和Python实现:
public class FlyingWuxia extends Wuxia implements IFly{ public FlyingWuxia(String name, char gender) { super(name, gender); } public FlyingWuxia(String name, char gender, int age) { super(name, gender, age); } @Override public String toString(){ return super.toString(); } @Override public void take_off(String tool) { System.out.println(this + " uses " + tool + " to take off!"); } @Override public void fly() { System.out.println(this + " is flying!"); } @Override public void landing() { System.out.println(this + " is landing!"); } @Override public void showStory(String whatHappened) { System.out.println(this + " experienced " + whatHappened); } }
class FlyingWuxia(Wuxia, IFly): def __init__(self, name, gender, age=20): Wuxia.__init__(self, name, gender, age) def take_off(self, tool): print(self, "uses ability", tool, "to take off!")
“飞行超人”的Java和Python实现:
public class FlyingSuperHero extends Hero implements IFly{ public FlyingSuperHero(String name, char gender) { super(name, gender, "U.S.A"); } public FlyingSuperHero(String name, char gender,int age) { super(name, gender, "U.S.A", age); } @Override public String toString(){ return super.toString(); } @Override public void take_off(String tool) { System.out.println(this + " uses " + tool + " to take off!"); } @Override public void fly() { System.out.println(this + " is flying!"); } @Override public void landing() { System.out.println(this + " is landing!"); } @Override public void showStory(String whatHappened) { System.out.println(this + " experienced " + whatHappened); } }
class FlyingSuperHero(Hero, IFly): def __init__(self, name, gender, age=20): Hero.__init__(self, name, gender, "U.S.A", age) def take_off(self, tool): print(self, "uses tool", tool, "to take off!")
Java和Python都是面向对象的编程语言,关于两者在面向对象方面的优劣,江湖上各派也各有各的观点。好比,Python虽然实现简单,可是它的封装特性有很大的问题,常常成为各路黑客们行走江湖、“行侠仗义”或“替天行道”的工具;而Java虽然可以作到类型安全,也体现了不少的设计原则,但毕竟实现过程颇费周折。在“李氏代换”这个原则下,对于这两个编程语言能够分别有以下思考:
//Java main函数中调用英雄示例: public static void main(String[] args) { Wuxia duanyu = new Wuxia("段誉", 'M', 19); duanyu.showAbility("六脉神剑"); demoStory(duanyu, "赶走慕容复"); System.out.println(""); //Python中这下一行是不能够的 Wuxia changqing = new FlyingWuxia("徐长卿", 'M', 26); changqing.showAbility("蜀山剑法"); demoTakeOff((FlyingWuxia)changqing, "御剑"); demoStory(changqing, "当了蜀山长老"); System.out.println(""); Hero captain = new FlyingSuperHero("Steven", 'M', 98); captain.showAbility("Flying"); //在Python中这也是不能够的 demoTakeOff((FlyingSuperHero)captain, "aegis"); System.out.println(""); } public static void demoTakeOff(IFly fly, String tool){ fly.take_off(tool); } public static void demoStory(IStory story, String whatHappened){ story.showStory(whatHappened); } # Python调用英雄人物示例: # If you did this: # changqing = Wuxia("徐长卿", 'M', 26) # you cannot do: # FlyingWuxia(changqing).take_off("御剑") in Python changqing = FlyingWuxia("徐长卿", 'M', 26) IAbility.showAbility(changqing, "蜀山剑法") IStory.showStory(changqing, "当了蜀山长老") changqing.take_off("御剑") print() captain = FlyingSuperHero("Steven", 'M', 98) captain.take_off("aegis") print() boeing757 = Airplane("Boeing 757") boeing757.take_off() boeing757.landing()
如下分别是java netbeans和python spyder下的运行效果:
金庸大侠和斯坦李大英雄带给咱们的青春记忆,以及程杰老师开创的故事体叙述软件设计模式的先河。