适配器
适配器模式适用于解决不同接口或不同系统间的兼容问题,想要修改旧系统的接口时应优先考虑使用适配器模式
下面是一个音乐播放器的例子
/**
* 适配器模式
*/
public class Adapter {
/**
* 新定义的接口
*/
interface MyMusicPlayer{
void play(String type,String filename);
}
/**
* 已存在的实现类
*/
class ExistPlayer{
public void playMP3(String filename){
System.out.println("mp3格式:"+filename);
}
public void playAvi(String filename){
System.out.println("avi格式:"+filename);
}
}
/**
* 适配器
*/
class MusicAdapter implements MyMusicPlayer{
private ExistPlayer existPlayer;
public MusicAdapter() {
this.existPlayer = new ExistPlayer();
}
@Override
public void play(String type, String filename) {
if (type.equalsIgnoreCase("mp3")) {
existPlayer.playMP3(filename);
} else if (type.equalsIgnoreCase("avi")) {
existPlayer.playAvi(filename);
}else {
System.out.println("error");
}
}
}
public static void main(String[] args) {
Adapter demo = new Adapter();
MusicAdapter adapter = demo.new MusicAdapter();
adapter.play("mp3","xxx.mp3");
adapter.play("avi","xxx.avi");
}
}
优点
可以让两个不相干的类一起运行,无需修改旧代码,灵活性好
缺点
适配器模式用多了会使整个系统变得很复杂,因为你调用的是适配器,却不知道适配器内部做了多少转换操作,所
以在能用别的办法解决问题时,尽量少用适配器模式
单例模式
懒汉式,也叫延迟加载,当需要使用实例时才会创建
class LazySingleObject{
private static LazySingleObject instance = null;
private LazySingleObject() {
}
public static synchronized LazySingleObject getInstance() {
if (instance == null) {
instance = new LazySingleObject();
}
return instance;
}
}
饿汉式,不管是否需要调用实例,都会先创建实例
class HungrySingleObject{
private static HungrySingleObject instance = new HungrySingleObject();
private HungrySingleObject() {
}
public static HungrySingleObject getInstance() {
return instance;
}
}
双重检查加锁,与懒汉相比提高了并发量
class HungrySingleObject{
private static HungrySingleObject instance = new HungrySingleObject();
private HungrySingleObject() {
}
public static HungrySingleObject getInstance() {
return instance;
}
}
静态内部类实现单例
class InnerSingleObject{
static class InSingleObject{
private static InnerSingleObject instance = new InnerSingleObject();
}
public static InnerSingleObject getInstance() {
return InSingleObject.instance;
}
}
优点:使用单例模式,对象内存中只有一个实例,无需频繁的创建和销毁对象,大大节省了性能消耗
缺点:没有。。。
工厂模式
工厂模式:简单来说就是将new对象的过程给封装起来,调用者无需关注
/**
* 工厂模式
*/
public class FactoryDemo {
/**
* 商品类
*/
static class Product{
void show(){};
}
/**
* 商品A
*/
static class ProductA extends Product{
@Override
public void show(){
System.out.println("this is productA...");
}
}
/**
* 商品B
*/
static class ProductB extends Product{
@Override
public void show(){
System.out.println("this is productB...");
}
}
/**
* 工厂
*/
static class Factory{
Product produce(String type){
if (type.equalsIgnoreCase("A")) {
return new ProductA();
} else if (type.equalsIgnoreCase("B")) {
return new ProductB();
}
return null;
}
}
/**
* 工厂提供者
*/
class Store{
private Factory factory;
public Store(Factory factory) {
this.factory = factory;
}
public Product create(String type){
return factory.produce(type);
}
}
public static void main(String[] args) {
FactoryDemo demo = new FactoryDemo();
Store store = demo.new Store(new Factory());
Product a = store.create("A");
a.show();
}
}
上述这种工厂模式,虽然增加了一个store类来便于以后扩展,但是当要增加Product的子类时和判断条件时,还需要修改工厂类的问题,不符合相应的开闭原则
下面使用 抽象工厂模式就不存在这种问题
抽象工厂模式
/**
* 抽象工厂模式
*/
public class AbstractFactoryDemo {
/**
* 商品类
*/
static class Product{
void show(){};
}
/**
* 商品A
*/
static class ProductA extends Product{
@Override
public void show(){
System.out.println("this is productA...");
}
}
/**
* 商品B
*/
static class ProductB extends Product{
@Override
public void show(){
System.out.println("this is productB...");
}
}
/**
* 抽象工厂
*/
static abstract class AbstractFactory{
abstract Product produce(String type);
}
/**
* 工厂A
*/
static class FactoryA extends AbstractFactory{
Product produce(String type){
System.out.print("FactoryA: ");
if (type.equalsIgnoreCase("A")) {
return new ProductA();
} else if (type.equalsIgnoreCase("B")) {
return new ProductB();
}
return null;
}
}
/**
* 工厂B
*/
static class FactoryB extends AbstractFactory{
Product produce(String type){
System.out.print("FactoryB: ");
if (type.equalsIgnoreCase("A")) {
return new ProductA();
} else if (type.equalsIgnoreCase("B")) {
return new ProductB();
}
return null;
}
}
/**
* 工厂提供者
*/
class Store{
private AbstractFactory factory;
public Store(AbstractFactory factory) {
this.factory = factory;
}
public Product create(String type){
return factory.produce(type);
}
}
public static void main(String[] args) {
AbstractFactoryDemo demo = new AbstractFactoryDemo();
Store store = demo.new Store(new FactoryA());
Product a = store.create("A");
a.show();
}
}
使用场景
- 如果new对象的代码需要增加或修改,有用工厂模式的话就只需要修改工厂中的代码即可。否则就需要大面积的修改代码了。这一点既是优点,也是缺点,因为它违背了开闭原则。
- 通过更换不同的工厂,可以实现对原有实现类整体变更。
- 设计模式的目的之一是让你的代码具有可扩展性,如果你new对象这一块的业务将来需要扩展,哪怕只是可能,那么也不要犹豫,用工厂模式吧。至于使用简单工厂还是抽象工厂,还得具体情况具体分析(简单工厂用的较多)。
简单工厂和抽象工厂的区别
简单工厂和抽象工厂有些区别,除了结构上的区别,主要区别在于使用场景不同。
简单工厂用于创建单一产品,将所有子类的创建过程集中在一个工厂中,如要修改,只需修改一个工厂即可。简单工厂经常和单例模式一起使用,例如用简单工厂创建缓存对象(文件缓存),某天需要改用redis缓存,修改工厂即可。
抽象工厂常用于创建一整个产品族,而不是单一产品。通过选择不同的工厂来达到目的,其优势在于可以通过替换工厂而快速替换整个产品族。例如上面的例子工厂A生产工厂A的产品A,工厂B生产工厂B的产品A。
优点
客户端与具体要创建的产品解耦,扩展性和灵活性高
缺点
增加要创建的对象时,需要增加的代码较多,会使系统变得较为复杂