Java经典面试题九:设计模式

问题一:单例模式

就是一个应用程序中,某个类的实例对象只有一个,没有办法去new,因为构造器是被private修饰的,一般通过getInstance()方法来获取实例。getInstance()方法的返回值是对象的引用,并不是一个新的实例。

单例式写法:

懒汉写法(线程不安全)

public class Singleton {

private static Singleton singleton;

private Singleton() {
}

public static Singleton getInstance() {
 if (singleton == null) {
  singleton = new Singleton();
 }
 return singleton;
}
}

懒汉写法,线程安全,加了个关键字synchronized

public class Singleton {  
   private static Singleton instance;  
   private Singleton (){}  
   public static synchronized Singleton getInstance() {  
   if (instance == null) {  
       instance = new Singleton();  
   }  
   return instance;  
   }  
}

饿汉写法 

public class Singleton {  
   private static Singleton instance = new Singleton();  
   private Singleton (){}  
   public static Singleton getInstance() {  
   return instance;  
   }  
}

静态内部类

public class Singleton {  
   private static class SingletonHolder {  
   private static final Singleton INSTANCE = new Singleton();  
   }  
   private Singleton (){}  
   public static final Singleton getInstance() {  
   return SingletonHolder.INSTANCE;  
   }  
}

枚举,不仅能避免多线程同步问题,还能防止反序列化重新创建对象 。

public enum Singleton {  
   INSTANCE;  
   public void whateverMethod() {  
   }  
}

双重校验锁

public class Singleton {  
   private volatile static Singleton singleton;  
   private Singleton (){}  
   public static Singleton getSingleton() {  
   if (singleton == null) {  
       synchronized (Singleton.class) {  
       if (singleton == null) {  
           singleton = new Singleton();  
       }  
       }  
   }  
   return singleton;  
   }  
}

问题二:观察者模式

对象间有一对多的依赖关系,当一状态发生改变,所有依赖它的对象都得到通知并自动更新。

一是被观察者,多是观察者;

示例:

public interface Person {
   //小王和小李通过这个接口可以接收到小美发过来的消息
   //小王和小李就是观察者,小美是被观察者
    void getMessage(String s);
}
public class XiaoWang implements Person {

   private String name = "小王";

   public XiaoWang() {
   }

   @Override
   public void getMessage(String s) {
       System.out.println(name + "接到了小美打过来的电话,电话内容是:" + s);
   }

}

public class XiaoLi implements Person {

   private String name = "小李";

   public XiaoLi() {
   }

   @Override
   public void getMessage(String s) {
       System.out.println(name + "接到了小美打过来的电话,电话内容是:->" + s);
   }

}
public class XiaoMei {
   List<Person> list = new ArrayList<Person>();
    public XiaoMei(){
    }

    public void addPerson(Person person){
        list.add(person);
    }

    //遍历list,把自己的通知发送给所有暗恋自己的人
    public void notifyPerson() {
        for(Person person:list){
            person.getMessage("你们过来吧,谁先过来谁就能陪我一起玩儿游戏!");
        }
    }
}

测试类:

public class Test {
   public static void main(String[] args) {

       XiaoMei xiao_mei = new XiaoMei();
       LaoWang lao_wang = new LaoWang();
       LaoLi lao_li = new LaoLi();

       //小王和小李在小美那里都注册了一下
       xiao_mei.addPerson(lao_wang);
       xiao_mei.addPerson(lao_li);

       //小美向小王和小李发送通知
       xiao_mei.notifyPerson();
   }
}

问题三:装饰者模式

对已有的逻辑业务进一步封装,使其增加额外功能,如Java中的io流就是,用户在使用的时候,可以任意组装,达到自己想要的效果。

示例:

public class Food {

   private String food_name;

   public Food() {
   }

   public Food(String food_name) {
       this.food_name = food_name;
   }

   public String make() {
       return food_name;
   };
}
//面包类
public class Bread extends Food {

   private Food basic_food;

   public Bread(Food basic_food) {
       this.basic_food = basic_food;
   }

   public String make() {
       return basic_food.make()+"+面包";
   }
}

//奶油类
public class Cream extends Food {

   private Food basic_food;

   public Cream(Food basic_food) {
       this.basic_food = basic_food;
   }

   public String make() {
       return basic_food.make()+"+奶油";
   }
}

//蔬菜类
public class Vegetable extends Food {

   private Food basic_food;

   public Vegetable(Food basic_food) {
       this.basic_food = basic_food;
   }

   public String make() {
       return basic_food.make()+"+蔬菜";
   }

}
public class Test {
   public static void main(String[] args) {
       Food food = new Bread(new Vegetable(new Cream(new Food("香肠"))));
       System.out.println(food.make());
   }
}

结果:香肠+奶油+蔬菜+面包

一层一层的封装

问题四:适配器模式

将两种完全不同的事物联系在一起,就像现实生活中的变压器。比如手机充电器,就可以把220V的电压和手机20V的电压联系在一起。

示例:

public class Test {
   public static void main(String[] args) {
       Phone phone = new Phone();
       VoltageAdapter adapter = new VoltageAdapter();
       phone.setAdapter(adapter);
       phone.charge();
   }
}

// 手机类
class Phone {

   public static final int V = 220;// 正常电压220v,是一个常量

   private VoltageAdapter adapter;

   // 充电
   public void charge() {
       adapter.changeVoltage();
   }

   public void setAdapter(VoltageAdapter adapter) {
       this.adapter = adapter;
   }
}

// 变压器
class VoltageAdapter {
   // 改变电压的功能
   public void changeVoltage() {
       System.out.println("正在充电...");
       System.out.println("原始电压:" + Phone.V + "V");
       System.out.println("经过变压器转换之后的电压:" + (Phone.V - 200) + "V");
   }
}

问题五:工厂模式

1.简单工厂模式:一个抽象接口,多个抽象接口的实现类,一个工厂类,用来实例化抽象接口。

// 抽象产品类
abstract class Car {
   public void run();

   public void stop();
}

// 具体实现类
class Benz implements Car {
   public void run() {
       System.out.println("Benz开始启动了。。。。。");
   }

   public void stop() {
       System.out.println("Benz停车了。。。。。");
   }
}

class Ford implements Car {
   public void run() {
       System.out.println("Ford开始启动了。。。");
   }

   public void stop() {
       System.out.println("Ford停车了。。。。");
   }
}

// 工厂类
class Factory {
   public static Car getCarInstance(String type) {
       Car c = null;
       if ("Benz".equals(type)) {
           c = new Benz();
       }
       if ("Ford".equals(type)) {
           c = new Ford();
       }
       return c;
   }
}

public class Test {

   public static void main(String[] args) {
       Car c = Factory.getCarInstance("Benz");
       if (c != null) {
           c.run();
           c.stop();
       } else {
           System.out.println("造不了这种汽车。。。");
       }

   }

}

工厂方法模式:抽象工厂类、具体工厂类、抽象产品类、具体产品类。

不再是由工厂类去实例化具体产品,而是抽象工厂的子类去实例化。

// 抽象产品角色
public interface Moveable {
   void run();
}

// 具体产品角色
public class Plane implements Moveable {
   @Override
   public void run() {
       System.out.println("plane....");
   }
}

public class Broom implements Moveable {
   @Override
   public void run() {
       System.out.println("broom.....");
   }
}

// 抽象工厂
public abstract class VehicleFactory {
   abstract Moveable create();
}

// 具体工厂
public class PlaneFactory extends VehicleFactory {
   public Moveable create() {
       return new Plane();
   }
}

public class BroomFactory extends VehicleFactory {
   public Moveable create() {
       return new Broom();
   }
}

// 测试类
public class Test {
   public static void main(String[] args) {
       VehicleFactory factory = new BroomFactory();
       Moveable m = factory.create();
       m.run();
   }
}

抽象工厂模式:与工厂方法模式不同,工厂方法模式中的工厂只生产单一的产品,而抽象工厂模式中的工厂可以生产多个产品。

/抽象工厂类
public abstract class AbstractFactory {
   public abstract Vehicle createVehicle();
   public abstract Weapon createWeapon();
   public abstract Food createFood();
}
//具体工厂类,其中Food,Vehicle,Weapon是抽象类,
public class DefaultFactory extends AbstractFactory{
   @Override
   public Food createFood() {
       return new Apple();
   }
   @Override
   public Vehicle createVehicle() {
       return new Car();
   }
   @Override
   public Weapon createWeapon() {
       return new AK47();
   }
}
//测试类
public class Test {
   public static void main(String[] args) {
       AbstractFactory f = new DefaultFactory();
       Vehicle v = f.createVehicle();
       v.run();
       Weapon w = f.createWeapon();
       w.shoot();
       Food a = f.createFood();
       a.printName();
   }
}

问题六:代理模式

静态代理:

1.目标类具有接口,并实现了其接口。
2.代理类也得实现目标类的接口,并有一个属性是目标类接口。
3.代理类的得有一个无参构造方法和一个构造方法,参数为目标类接口类型,用于接收目标对象赋值给代理类的目标类接口属性。
4.代理类必须实现接口的所有方法,并在在方法中访问目标类对象的方法,在访问之前和之后都可以进行一些代理操作。
示例:

1.创建目标类接口MassegeService。


public interface MassegeService {
public void sendMessage1();
public void sendMessage2();
public void sendMessage3();
}

2.创建目标类MassegeServiceImpl并实现接口。

public class MassegeServiceImpl implements MassegeService {
	/**
	 * 业务逻辑实现类(被代理类)
	 */
	public MassegeServiceImpl() {
		// TODO Auto-generated constructor stub
	}
	public void sendMessage1() {
		// TODO Auto-generated method stub
    System.out.println("hello maven");
	}

	public void sendMessage2() {
		// TODO Auto-generated method stub
		   System.out.println("hello Spring");
	}

	public void sendMessage3() {
		// TODO Auto-generated method stub
		System.out.println("hello mybatis");
	}
}

3.创建代理类staticProxy并实现目标对象的接口,写有参造方法

public class staticProxy implements MassegeService {
	MassegeService ms;//引入接口
	protected staticProxy() {//将无参构造修饰为受保护的,一般项目分包处理,代理。同子类才能调用无参。
		
	}
	public staticProxy(MassegeService ms) {//有参构造,传入被代理实例(目标对象),使用代理。
		this.ms=ms;
	}
  public void validatorInfo(){  //服务方法,业务为逻辑处理
	System.out.println("完成数据验证操作。");
  }
	public void sendMessage1() {
     this.validatorInfo();    
		ms.sendMessage1();
	}
	public void sendMessage2() {
	
	     this.validatorInfo();    
			ms.sendMessage2();
	}
	public void sendMessage3() {
	     this.validatorInfo();    
			ms.sendMessage3();
	}
}

4.创建测试ProxyTest类通过代理访问目标类方法。

public class ProxyTest {
	public ProxyTest() {
		// TODO Auto-generated constructor stub
	}
	 
	 public void testStatic(){
	 //通过传目标对象实例获取代理类,通过代理类对象访问目标对象实例方法。
		 MassegeService ms =new staticProxy(new  MassegeServiceImpl());
		 ms.sendMessage1();
		 ms.sendMessage2();
		 ms.sendMessage3();
	 }

	public static void main(String[] args) {
		// TODO Auto-generated method stub
       ProxyTest pt=new ProxyTest();
       pt.testStatic();
	}

}

动态代理:动态代理类必须实现Invocation接口,并且实现invoke() 方法,在invoke()方法中需要完成两件事情:一是添加服务,二是调用业务逻辑方法。代理服务就是在代理类中的invoke中执行的。我们可以通过反射机制获取目标对象的加载类、接口,还有实现了Invocation接口的代理类传到Proxy.newProxyInstance(被代理类,被代理类接口,代理类)方法中获取到代理类的对象实例。

示例:

1.创建动态代理类DynamicProxy,实现Invocation接口,并实现invoke() 方法。并提供一个方法获取代理类实例,即bin(Object oj)方法。

public class DynamicProxy implements InvocationHandler {
	private Object obj;
	public DynamicProxy() {	//无参构造
	}
     public Object bin(Object obj){//参数传入被代理对象,返回代理对象实例
    	 this.obj=obj;
    	 return Proxy.newProxyInstance(obj.getClass().getClassLoader(), obj.getClass().getInterfaces(), this);//代理中的invoke()方法在这Proxy.newProxyInstance()中执行
     }
     public void validatorInfo(){  //服务方法,业务为逻辑处理
    		System.out.println("完成数据验证操作。");
    	  }
	public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
		Object obj=null;
		this.validatorInfo();
		obj=method.invoke(this.obj, args);
		return obj;
	}
}

2.创建被代理类即其接口,此次还是使用MassegeServiceImpl类和MassegeServiceImpl接口,代码详见静态代理。

3.创建测试类ProxyTest,测试动态代理实现。

public class ProxyTest {
	public ProxyTest() {
		// TODO Auto-generated constructor stub
	}
	 public void testDynamic(){
		 MassegeService ms =(MassegeService) new DynamicProxy().bin(new MassegeServiceImpl());
		 ms.sendMessage1();
		 ms.sendMessage2();
		 ms.sendMessage3();
	 }
	public static void main(String[] args) {
		// TODO Auto-generated method stub
       ProxyTest pt=new ProxyTest();
       pt.testDynamic();
	}
}

问题七:简单工厂和抽象工厂有什么区别?

简单工厂模式本身很简单。一般用于小项目或产品很少扩展的情况。

有三种角色组成:

工厂类角色:简单工厂模式的核心,含有一定商业逻辑和判断逻辑,根据逻辑不同,产生具体的工厂产品;

抽象产品角色:一般是具体产品继承的父类或实现的接口,由接口或抽象类来实现;

具体产品角色:工厂类所创建的对象就是此角色的实例。

 

抽象工厂模式和工厂方法模式的区别在于需要创建对象的复杂程度上。

抽象工厂模式是简单工厂模式、工厂方法模式里最抽象、最具一般性的。

抽象工厂模式用意为:给客户端提供一个接口,可以创建多个产品族(?)中的产品对象。

抽象工厂模式的角色,和工厂方法差不多:

抽象工厂角色:这是工厂方法模式的核心,是具体工厂角色必须实现的接口或必须继承的父类。

具体工厂角色:含有和具体业务逻辑有关的代码。由应用程序调用创建对应的具体产品的对象

抽象产品角色:是具体产品继承的父类或者是实现的接口

具体产品角色:具体工厂角色创建的对象就是此角色的实例

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值