软件设计原则
开闭原则
对扩展开放,对修改关闭。在程序需要进行拓展的时候,不能去修改原有的代码,实现一个热插拔的效果。简言之,是为了使程序的扩展性好,易于维护和升级。
想要达到这样的效果,需要使用接口和抽象类。
因为抽象灵活性好,适应性广,只要抽象的合理,可以基本保持软件架构的稳定。而软件中易变的细节可以从抽象派生来的实现类来进行扩展,当软件需要发生变化时,只需要根据需求重新派生一个实现类来扩展就可以了。
public abstract class AbstractSkin {//显示的方法public abstract void display();
}
public class DefaultSkin extends AbstractSkin {@Overridepublic void display() {System.out.println("默认皮肤");}
}
public class MySkin extends AbstractSkin{@Overridepublic void display() {System.out.println("我的皮肤");}
}
public class SougouInput {private AbstractSkin skin;public void setSkin(AbstractSkin skin) {this.skin = skin;}public void display() {skin.display();}
}
public class Client {public static void main(String[] args) {//创建搜狗输入法SougouInput sougouInput = new SougouInput();//创建皮肤//AbstractSkin skin = new DefaultSkin();AbstractSkin skin = new MySkin();//设置皮肤sougouInput.setSkin(skin);//显示皮肤sougouInput.display();}
}
里氏代换原则
里氏代换原则:任何基类可以出现的地方,子类一定可以出现。通俗理解:子类可以扩展父类的功能,但不能改变父类原有的功能。换句话说,子类继承父类时,除添加新的方法完成新增功能外,尽量不要
重写父类的方法。
如果通过重写父类的方法来完成新的功能,这样写起来虽然简单,但是整个继承体系的可复用性会比较差,特别是运用多态比较频繁时,程序运行出错的概率会非常大。
public interface Quadrilateral {//获取长double getLength();//获取宽double getWidth();
}
public class Rectangle implements Quadrilateral {private double length;private double width;public void setLength(double length) {this.length = length;}public void setWidth(double width) {this.width = width;}@Overridepublic double getLength() {return length;}@Overridepublic double getWidth() {return width;}
}
public class Square implements Quadrilateral {private double side;public double getSide() {return side;}public void setSide(double side) {this.side = side;}@Overridepublic double getLength() {return side;}@Overridepublic double getWidth() {return side;}
}
public class RectangleDemo {public static void main(String[] args) {//创建长方形对象Rectangle rectangle = new Rectangle();//设置长和宽rectangle.setLength(20);rectangle.setWidth(10);//调用方法进行扩展操作resize(rectangle);//打印长和宽printLengthAndWidth(rectangle);}//扩宽的方法public static void resize(Rectangle rectangle) {//判断宽度是否小于长度,如果小于则将宽度+1while (rectangle.getLength() >= rectangle.getWidth()) {rectangle.setWidth(rectangle.getWidth() + 1);}}//打印长和宽public static void printLengthAndWidth(Quadrilateral quadrilateral) {System.out.println(quadrilateral.getLength());System.out.println(quadrilateral.getWidth());}
}
依赖倒转原则
高层模块不应该依赖低层模块,两者都应该依赖其抽象;抽象不应该依赖细节,细节应该依赖抽象。简单的说就是要求对抽象进行编程,不要对实现进行编程,这样就降低了客户与实现模块间的耦合。
public interface Cpu {//运行cpupublic void run();
}
public class IntelCpu implements Cpu {public void run() {System.out.println("使用Intel处理器");}
}
public interface HardDisk {//存储数据public void save(String data);//获取数据public String get();
}
public class XiJieHardDisk implements HardDisk {public void save(String data) {System.out.println("使用希捷硬盘存储数据" + data);}public String get() {System.out.println("使用希捷希捷硬盘取数据");return "数据";}
}
public interface Memory {//存储数据public void save();
}
public class KingstonMemory implements Memory {public void save() {System.out.println("使用金士顿作为内存条");}
}
public class Computer {private HardDisk hardDisk;private Memory memory;private Cpu cpu;public HardDisk getHardDisk() {return hardDisk;}public void setHardDisk(HardDisk hardDisk) {this.hardDisk = hardDisk;}public Memory getMemory() {return memory;}public void setMemory(Memory memory) {this.memory = memory;}public Cpu getCpu() {return cpu;}public void setCpu(Cpu cpu) {this.cpu = cpu;}public void run() {System.out.println("计算机工作");String data = hardDisk.get();System.out.println("从硬盘中获取的数据为:" + data);cpu.run();memory.save();}
}
public class ComputerDemo {public static void main(String[] args) {//创建计算机的组件对象HardDisk hardDisk = new XiJieHardDisk();Memory memory = new KingstonMemory();Cpu cpu = new IntelCpu();//创建计算机对象Computer computer = new Computer();//组装计算机computer.setCpu(cpu);computer.setHardDisk(hardDisk);computer.setMemory(memory);//运行计算机computer.run();}
}
接口隔离原则
客户端不应该被迫依赖于它不使用的方法;一个类对另一个类的依赖应该建立在最小的接口上。
public interface Waterproof {void waterproof();
}
public interface Fireproof {void fireproof();
}
public interface AntiTheft {void antiTheft();
}
public class HeiMaSafetyDoor implements AntiTheft, Fireproof, Waterproof {public void antiTheft() {System.out.println("防盗");}public void fireproof() {System.out.println("防火");}public void waterproof() {System.out.println("防水");}
}
public class ItcastSafetyDoor implements AntiTheft, Fireproof {public void antiTheft() {System.out.println("防盗");}public void fireproof() {System.out.println("防火");}
}
public class Client {public static void main(String[] args) {//创建安全门对象HeiMaSafetyDoor door = new HeiMaSafetyDoor();//调用功能door.antiTheft();door.fireproof();door.waterproof();System.out.println("====================");ItcastSafetyDoor door1=new ItcastSafetyDoor();door1.antiTheft();door1.fireproof();}
}
迪米特法则
迪米特法则又叫最少知识原则。
其含义是:如果两个软件实体无须直接通信,那么就不应当发生直接的相互调用,可以通过第三方转发该调用。其目的是降低类之间的耦合度,提高模块的相对独立性。
public class Star {private String name;public Star(String name) {this.name = name;}public String getName() {return name;}
}
public class Fans {private String name;public Fans(String name) {this.name = name;}public String getName() {return name;}
}
public class Company {private String name;public Company(String name) {this.name = name;}public String getName() {return name;}
}
public class Agent {private Star star;private Fans fans;private Company company;public void setStar(Star star) {this.star = star;}public void setFans(Fans fans) {this.fans = fans;}public void setCompany(Company company) {this.company = company;}//和粉丝见面的方法public void meeting() {System.out.println(fans.getName() + "与明星" + star.getName() + "见面 了。");}//和公司洽谈业务的方法public void business() {System.out.println(company.getName() + "与明星" + star.getName() + "洽淡业务。");}
}
public class Client {public static void main(String[] args) {//创建经纪人类Agent agent = new Agent();//创建明星对象Star star = new Star("林青霞");agent.setStar(star);//创建粉丝对象Fans fans = new Fans("王祖贤");agent.setFans(fans);//创建公司对象Company company = new Company("阿里巴巴");agent.setCompany(company);//和粉丝见面agent.meeting();//和媒体公司洽谈业务agent.business();}
}
合成复用原则
合成复用原则是指:尽量先使用组合或者聚合等关联关系来实现,其次才考虑使用继承关系来实现
通常类的复用分为继承复用和合成复用两种:
继承复用虽然有简单和易实现的优点,但它也存在以下缺点:
- 继承复用破坏了类的封装性。因为继承会将父类的实现细节暴露给子类,父类对子类是透明的,所以这种复用又称为“白箱”复用。
- 子类与父类的耦合度高。父类的实现的任何改变都会导致子类的实现发生变化,这不利于类的扩展与维护。
- 它限制了复用的灵活性。从父类继承而来的实现是静态的,在编译时已经定义,所以在运行时不可
能发生变化。
采用组合或聚合复用时,可以将已有对象纳入新对象中,使之成为新对象的一部分,新对象可以调用已有对象的功能,它有以下优点:
- 它维持了类的封装性。因为成分对象的内部细节是新对象看不见的,所以这种复用又称为“黑箱” 复用。
- 对象间的耦合度低。可以在类的成员位置声明抽象。
- 复用的灵活性高。这种复用可以在运行时动态进行,新对象可以动态地引用与成分对象类型相同的 对象。