如果出現了 "胖" interface 代表他應該是可以分解成多組。
底下是一個 "胖" interface 的範例
首先一開始客戶要求我們做一台車,很簡單的我們直接使用了 interface Vehicle ,
之後不管是摩托車,跑車,房車,中古車 都可以使用他
interface Vehicle { void Run(); } class Porsche911 implements Vehicle { @Override public void Run() { // TODO Auto-generated method stub System.out.println("Porsche911 Running"); } } public class Car implements Vehicle{ /** * @param args */ public static void main(String[] args) { // TODO Auto-generated method stub Vehicle carVehicle = new Car(); carVehicle.Run(); carVehicle = new Porsche911(); carVehicle.Run(); } @Override public void Run() { // TODO Auto-generated method stub System.out.println("Car Running"); } }
但是好景不常,某一天客戶提出了新的需求,
他們公司生產了飛天車,這也代表著我們的程式也必須提供飛天車的資料
下面的作法是比較不好的作法
interface Vehicle { void Run(); void Fly(); } class Porsche911 implements Vehicle { @Override public void Run() { // TODO Auto-generated method stub System.out.println("Porsche911 Running"); } @Override public void Fly() { // TODO Auto-generated method stub System.out.println("Porsche911 not Flying"); } } class FlyCar implements Vehicle { @Override public void Run() { // TODO Auto-generated method stub System.out.println("FlyCar Running"); } @Override public void Fly() { // TODO Auto-generated method stub System.out.println("FlyCar flying"); } } public class Car implements Vehicle{ /** * @param args */ public static void main(String[] args) { // TODO Auto-generated method stub Vehicle carVehicle = new Car(); carVehicle.Run(); carVehicle = new Porsche911(); carVehicle.Run(); } @Override public void Run() { // TODO Auto-generated method stub System.out.println("Car Running"); } @Override public void Fly() { // TODO Auto-generated method stub System.out.println("Car not Flying"); } }
可以很清楚的發現,在interface裡新增了 fly這個功能,但是這其實是災難的開始,
這使得原本跑的很正常的 car and Porsh911 這兩個物件也新增了fly的功能,
但是他們並不會飛阿,而且他們也不想要會飛,可是他們現在逼不得以也必須implement Fly這個功能,這樣寫法非常不好的原因在於,
- implement的功能並不是我們所需要的
- 現在只有兩個class需要做修正(Car and Porsh911),當我們有一千個class要修改的時候我相信修改的人一定會......!@#$%
所以根據上面的例子我們可以做以下的修改
interface Vehicle { void Run(); } interface FlyVehicle extends Vehicle { void Fly(); } class Porsche911 implements Vehicle { @Override public void Run() { // TODO Auto-generated method stub System.out.println("Porsche911 Running"); } } class FlyCar implements FlyVehicle { @Override public void Run() { // TODO Auto-generated method stub System.out.println("FlyCar Running"); } @Override public void Fly() { // TODO Auto-generated method stub System.out.println("FlyCar flyning"); } } public class Car implements Vehicle{ /** * @param args */ public static void main(String[] args) { // TODO Auto-generated method stub Vehicle carVehicle = new Car(); carVehicle.Run(); carVehicle = new Porsche911(); carVehicle.Run(); carVehicle = new FlyCar(); ((FlyVehicle)carVehicle).Fly(); } @Override public void Run() { // TODO Auto-generated method stub System.out.println("Car Running"); } }
我們使用interface FlyVehicle繼承 Vehicle 並新增 fly的功能,
這邊其實跟SingleResponsibilityPrinciple的感覺很像,每個interface都有單一的職責(注意不是單一method)這使得我們只需要修改FlyVehicle就可以了,而且新增功能對於其他的class並不會造成額外的影響。
當然這種修改方式僅限於開發階段,
- 在小怪物還沒有長成千年老妖之前處理是很容易的...
如果是處在維護階段的話,上面的作法可能會牽一髮而動全身,如果能動就動吧,如果不能動就....,試試下面的方法吧
interface Vehicle { void Run(); void Fly(); } abstract class VehicleAdapter implements Vehicle { abstract public void Run(); public void Fly() { System.out.println("Do Nothing"); } } class Porsche911 extends VehicleAdapter { public void Run() { // TODO Auto-generated method stub System.out.println("Porsche911 Running"); } } class FlyCar extends VehicleAdapter { @Override public void Run() { // TODO Auto-generated method stub System.out.println("FlyCar Running"); } @Override public void Fly() { // TODO Auto-generated method stub System.out.println("FlyCar flyning"); } } public class Car extends VehicleAdapter{ /** * @param args */ public static void main(String[] args) { // TODO Auto-generated method stub Vehicle carVehicle = new Car(); carVehicle.Run(); carVehicle = new Porsche911(); carVehicle.Run(); carVehicle = new FlyCar(); carVehicle.Fly(); } @Override public void Run() { // TODO Auto-generated method stub System.out.println("Car Running"); } }
上面使用了一個adapter轉接器將Fly這個功能在adapter中做掉,使得繼承vehicleAdapter的物件不再需要實做fly這個功能,然後Flycar可以override掉原本的功能,改成fly的功能。用這樣的方式就可以使之後想使用vehicle interface但不想fly的人,可以使用新的選擇而不再需要去實做Fly這個功能。
ISP原則感覺就是將SRP原則套在interface身上,希望每個interface都是單一原則(不是單一method),而不是一個interface擁有多個責任,太胖的interface會造成許多問題,
善用這個方法,可以降低耦合,使程式碼更加彈性。
沒有留言:
張貼留言