Java常用的设计原则和设计模式
1.常用的设计原则
1.1软件开发的流程
- 需求分析文档,概要设计文档,编码和测试,安装和调试,维护和升级
1.2常用的设计原则
- 开闭原则
对扩展开放,对修改关闭
若需在类中添加成员变量或成员方法时,新建一个类继承该类,不能在原代码中修改
- 里氏代换原则
任何基类可以出现的地方,子类一定可以出现
尽量使用多态,适用于多个子类所调用的方法相同
//父类,形状
public class Shape{ public void show(); }
//子类,矩形,圆形
public class Rectangle extends Shape{ public void show(); }
public class Circle extends Shape{ public void show(); }
//测试类
public class ShapeTest{
//自定义成员方法实现将参数指定的矩形对象打印出来
public static void draw(Rectangele r){
r.show();
}
//自定义成员方法实现将参数指定的圆形对象打印出来
publi static void draw (Circle c){
c.show();
}
//多态实现打印任意Shape子类的对象
Shape s1 = new Rectangle();
Shape s2 = new Circle();
public static void draw(Shape s){
s.show();
}
}
- 依赖倒转原则
尽量多依赖于抽象类或接口而不是具体实现类,对子类有强制性和规范性
- 接口隔离原则
尽量使用小接口而不是大接口,降低类之间的耦合度
//例如创建一个Animal接口,需要包含run()和fly()方法
public interface Animal{
void run();
void fly();
}
//新建一个Dog类继承接口,则需要重写run方法和fly方法,显然不合理。所以这里使用小接口RunAnimal和FlyAnimal
public interface RunAnimal{ void run(); }
public class Dog implements RunAnimal{
@Override
public void run(){}
}
- 迪米特法则(最少知道原则)
一个实体应当尽量少与其他实体之间发生相互作用,使系统功能模块相对独立。高内聚 低耦合
- 合成复用法则
尽量使用合成/聚合的方式,而不是继承的方式
public Other{ public void show(); }
//需要在当前类中使用其他类的方法或变量时,尽量不采取继承,而是把其他类的引用声明为当前类的成员变量,通过构造方法来实现调用
public class Present /*extends Other*/ {
private Other other;//合成复用
public Present(Other other){
this.other = other;
}
public void test(){
//调用其他类中的show方法
other.show();
}
}
2.常用的设计模式
- **创建型模式:**单例设计模式,工厂方法模式,抽象工厂模式
- **结构型模式:**装饰器模式,代理模式
- **行为型模式:**模板模式
2.1单例设计模式
- 饿汉式:new对象时直接定义
Object obj = new Object();
- 懒汉式:(存在多线程同步处理的问题)new对象时不直接定义
Object obj = null;
/**
*懒汉式举例
*/
public class Singleton{
//声明本类类型的引用指向本类类型的对象并使用private static修饰
private static Singleton sin = null;
//私有化构造方法
private Singleton(){}
//提供共有的get方法负责返回上述生成的对象
public static /*synchronized*/ Singleton getInstance(){//……①
synchronized(Singleton.class){//……②
if(null == sin){
sin = new Singleton();
}
return sin;
}
}
}
/**
*1.假设有多个线程同时访问getInstance方法,第一个线程还未创建完毕sin对象,后续的线程检测到sin = null成立,故最终会创建多个线程。
*2.可以在方法名前加synchronized关键字修饰加锁,如①所示。
*3.也可以在方法内部用synchronized修饰类名,如②所示。
*/
//为防止每次调用getInstance方法都要加锁,首先判断sin是否为null,于是方法变成
public static /*synchronized*/ Singleton getInstance(){//……①
if(null == sin){
synchronized(Singleton.class){//……②
if(null == sin){
sin = new Singleton();
}
}
}
return sin;
}
2.2工厂方法模式
2.2.1普通工厂模式
建立一个工厂类,对实现了同一接口的不同实现类进行实例的创建
- ***UML类图***的方法和属性的访问权限
SendFactory中produce方法返回的是Sender接口实现的MailSender类或SmsSender类
**注意:**如果传递到produce中的参数出错,则不能正确创建对象,并且可能出现空指针异常。
2.2.2多个工厂模式
**主要缺点:**首先需要创建工厂类的对象。
2.2.3静态工厂模式
- 适用于大量对象的创建
2.2.4抽象工厂模式
2.3装饰器模式
**装饰器模式就是给一个对象动态地增加一些新功能,要求装饰对象和被装饰对象实现同一个接口,装饰对象有被装饰对象的实例。
***装饰器模式***是将原有对象作为一个参数传递给装饰器的构造器。
public class Decorator implements Souceable {
private Sourceable source;
public Decorator(Sourceable source) {
this.source = source;
}
@Override
public void method() {
soiurce.method();//保证原有功能不变的基础上增加修饰
System.out.println("这里是修饰语句。");
}
}
- 可以实现类功能的扩展,缺点是会产生很多相似的类。
2.4代理模式
***代理模式***是在代理类中创建一个被代理的对象。
- 装饰器模式关注于在一个对象上动态地添加方法,而代理模式关注于控制对对象的访问。
2.5模板方法模式
一个抽象类中封装了一个固定流程,流程中的具体步骤可以由不同子类进行不同的实现,通过抽象类让固定的流程产生不同的结果。
public class AbstractCalculator {
public int splitExpression(String exp, String op) {//exp为运算式,op为其中的运算符
String[] sArr = exp.split(op);
return calculate(Integer.parseInt(sArr[0], Integer.parseInt(sArr[1])));//将分割开的两个运算数传递给calculate方法
}
//建立抽象方法,规范计算流程,由不同子类实现
public abstract int calculate(int num_a, int num_b);
}
//-----------------------------------
public class Plus extends AbstractCalculator {
@Override
public int calculator(int num_a, int num_b) {
return num_a + num_b;
}
}
//-----------------------------------
public class AbstractCalculatorTest {
public static void main(String[] args) {
AbstractCalculator ac = new Plus();
int res = ac.splitExpression("1+1", "\\+");
System.out.println("运算结果是:" + res);
}
}