设计模式和类之间的关系

一、设计模式

    1.设计模式分类

       常用设计模式可以分为三类创建模式、结构模式、行为模式

       创建模式:Factory、Builder、Singleton

       结构模式:Adapter、Decorator、Flyweight、Proxy

       行为模式:State、Memento、Observer、Strategy、Visitor

    2.工厂模式

       案例:我们经常需要new 一些Dao类,或在new Dao之前做一些准备工作,可以用工厂模式。

       要点:把创建工作交给工厂类实现

public class FactoryTest
{
    
    public static void main(String[] args)
    {
        UserDao uDao = (UserDao)DaoFactory.getDao("test.UserDao");
        uDao.login();
        uDao.logout();
    }
    
}

//面向接口编程习惯
interface IDao
{
    void login();
}
//实现类,里面除了实现接口方法还可以有自己的方法
class UserDao implements IDao
{
    @Override
    public void login()
    {
        System.out.println("user login!");
        
    }
    
    public void logout()
    {
        System.out.println("user logout!");
    }
}
//工厂类主要负责类对象的创建
class DaoFactory
{
    public static IDao getDao(String DaoName)
    {
        IDao dao = null;
        try
        {
            dao = (IDao)Class.forName(DaoName).newInstance();
        }
        catch (Exception e)
        {
            e.printStackTrace();
        }
        
        return dao;
    }
}

    3.建造模式

       案例:假设一个复杂的对象由多个部件组成,并且改变的机会较大,我们可以考虑将该对象的创建分开实现,部件的创建和部件的组合

       要点:一个类专门负责部件创建,另一个类专门负责部件的组装

public class BuilderTest
{
    public static void main(String[] args)
    {
        Combination combination = new Combination(new Create());
        combination.buile();
    }
}

// 负责创建部件的类
class Create
{
    // 创建A部件
    public String createA()
    {
        return "A";
    }
    
    // 创建B部件
    public String createB()
    {
        return "B";
    }
    
    // 创建C部件
    public String createC()
    {
        return "C";
    }
}
//负责组合部件的类
class Combination
{
    private Create creater;
    public Combination(Create create)
    {
        this.creater = create;
    }
    //组装部件
    public void buile()
    {
        String str = creater.createA()+creater.createB()+creater.createC();
        System.out.println(str);
    }
    
}

    4.单例模式

       案例:在一个项目中我们用到读取文件的类,这个类的使用又不是很频繁我们可以考虑用单例模式去做。

       要点:在整个系统中保证该对象只有一个实例

public class SingletonTest
{
    public static void main(String[] args)
    {
        FileOpe fo1 = FileOpe.getInstance();
        fo1.createFile();
        FileOpe fo2 = FileOpe.getInstance();
        fo2.createFile();
        
    }
    
    
}
class FileOpe
{
    private static FileOpe fo = null;
    //这里保证不管有多少个线程系统中只有一个该类实例
    public synchronized static FileOpe getInstance()
    {
        if(fo == null)
        {
            fo = new FileOpe();
        }
        return fo;
    } 
    //私有构造方法是关键确保类的实例化只能在该类内部进行
    private FileOpe()
    {
        System.out.println("constructor going !");
    }
    
    public void createFile()
    {
        System.out.println("create File !");
    }
}

    5.适配器模式

       案例:编写一个类图像清晰化A,同时清晰化之后就要为图像去噪声B

       要点:把扩展模块注入到主模块中去使用(单项适配器模式)

public class AdapterTest
{
    public static void main(String[] args)
    {
        SubA suba = new SubA(new SubB());
        suba.funA();
    }
}
//主模块
class A
{
    public void funA()
    {
        System.out.println("图像清晰化");
    }
}
//扩展模块
interface B
{
    void funB();
}
class SubB implements B
{
    @Override
    public void funB()
    {
        System.out.println("图像去噪音");
    }
}
//重写主模块,把扩展模块注入到主模块中
class SubA extends A
{
    private B b;
    public SubA(B b)
    {
        this.b = b;
    }
    @Override
    public void funA()
    {
        super.funA();
        b.funB();
    }
}


    6.装饰模式

       案例:编写一个读取字符串的类ReadString,之后又要增加新的功能把读到的字符串转换成大写字母使用。

       要点:把主模块注入到扩展模块

public class DecoratorTest
{
    public static void main(String[] args)
    {
        //这里可以类比一下文件读写操作 BufferedReader br=new BufferedReader(new FileReader(new File("")));
        Change change = new Change(new ReadString());
        change.changeString();
    }
}
//定义主模块接口以便于主模块的扩展
interface IRead
{
    void read();
}
//主模块
class ReadString implements IRead
{
    @Override
    public void read()
    {
        System.out.println("读取字符串");
    }
}
//扩展模块
class Change
{
    private IRead iRead;
    public Change(IRead iRead)
    {
        this.iRead = iRead;
    }
    public void changeString()
    {
        iRead.read();
        System.out.println("转换为大写字母");
    }
}

    7.代理模式

       案例:西门庆要勾搭潘金莲,需要王婆做代理 。
       要点:表面上是西门庆跟王婆勾搭,其实是和潘金莲勾搭。

public class ProxyTest
{
    public static void main(String[] args)
    {
        Wangpo wangpo = new Wangpo();
        wangpo.makeEyesWithMan();
        wangpo.happyWithman();
    }
}
//定义王婆、潘金莲一类的女人
interface KindWomen
{
    void makeEyesWithMan();
    void happyWithman();
}
//定义潘金莲是什么样的女人
class PanJinLian implements KindWomen
{
    @Override
    public void makeEyesWithMan()
    {
        System.out.println("潘金莲抛媚眼。");
    }
    @Override
    public void happyWithman()
    {
        System.out.println("潘金莲happy中...");
    }
}
//定义王婆是什么样的女人
class Wangpo implements KindWomen
{
    KindWomen women;
    //默认情况下让潘金莲代理
    public Wangpo()
    {
        this.women = new PanJinLian();
    }
    //可以让任何一个女人代理
    public Wangpo(KindWomen women)
    {
        this.women = women;
    }
    @Override
    public void makeEyesWithMan()
    {
        women.makeEyesWithMan();//实际上上让别人代理做事
    }
    @Override
    public void happyWithman()
    {
        women.happyWithman();//实际上上让别人代理做事
    }
}


    8.享元模式

         案例:一些文字软件中经常会出现大量相同的字,每个就是一个对象,我们可以使用享元模式使这些字共同有一个对象表示。

         要点:避免大量拥有相同内容的小类的开销,使大家共同使用一个对象。

public class Flyweight
{
    public static void main(String[] args)
    {
        Word w1 = WordPool.getWorld("1","刘德华");
        Word w2 = WordPool.getWorld("2","张学友");
        Word w3 = WordPool.getWorld("1","刘德华");
        Word w4 = WordPool.getWorld("1","刘德华");
    }
}
//享元类
class Word
{
    private String content;
    private String key;
    public Word(String content,String key)
    {
        this.content = content;
        this.key = key;
        System.out.println("构造实例"+key);
    }
}
//享元池,可以用map存贮
class WordPool
{
    private static Map<String,Word> pool = new HashMap<String, Word>();
    public static Word getWorld(String key,String content)
    {
        Word word = pool.get(key);
        if(word == null)
        {
            word = new Word(key,content);
            pool.put(key, word);
        }
        return word;
    }
}


    9.观察者模式

         案例:某商店的商品价格变化时要通知该商店的会员朋友

         要点:观察者和被观察者互不认识

public class ObserverTest
{
    public static void main(String[] args)
    {
        Product p = new Product("小白菜",5);
        Customer c = new Customer();
        p.addObserver(c);//调用继承Observable的方法添加观察者可以添加多个。
        p.changePrice(7);
    }
}
class Product extends Observable
{
    public String pname;
    public double price;
    
    public Product(String pname,double price)
    {
        this.pname = pname;
        this.price = price;
    }
    //商品加个发生变化
    public void changePrice(double price)
    {
        this.price = price;
        this.setChanged();//设置变化点通知观察者价格变化
        this.notifyObservers("价格变化");//通知所有的观察者一个消息,这里会自动调用观察者的Update方法。
    }
}
//观察者
class Customer implements Observer
{
    //继承方法第一个参数为被观察的对象,第二个参数为发来的消息
    @Override
    public void update(Observable obs, Object obj)
    {
        System.out.println(((Product)obs).pname+":"+obj.toString());
    }    
}


    10.策略模式

         案例:赵云拿着三个锦囊去东吴给刘备娶老婆,锦囊里面是诸葛亮给的三个妙计

         要点:用不同策略装锦囊,锦囊就可以做不同的事。

public class StrategyTest
{
    public static void main(String[] args)
    {
        //赵云执行方法
        Context context ;
        context = new Context(new BackDoor());
        context.operate();
        context = new Context(new GivenGreenLight());
        context.operate();
        context = new Context(new BlockEnemy());
        context.operate();
    }
}

//首先定义一个策略的接口
interface IStrategy
{
    //每个策略里面都要有一个可执行的算法
    void operate();
}

//策略1:找乔国老帮忙
class BackDoor implements IStrategy
{
     //策略方法
    @Override
    public void operate()
    {
        System.out.println("找乔国老帮忙,让吴国太给孙权施加压力");
    }    
}
//策略2:求吴国太
class GivenGreenLight implements IStrategy
{
    
    @Override
    public void operate()
    {
        System.out.println("求吴国太开绿灯,放行");
    }
}
//策略3:孙夫人断后
class BlockEnemy implements IStrategy
{

    @Override
    public void operate()
    {
        System.out.println("孙夫人断后,阻击追兵");
    }
}
//锦囊:存放策略
class Context
{
    private IStrategy strategy;
    public Context(IStrategy strategy)
    {
        this.strategy = strategy;
    }
    //执行策略
    public void operate()
    {
        strategy.operate();
    }
}


 二、类与类之间的关系

    1.继承关系

        继承指的是一个类(称为子类、子接口)继承另外的一个类(称为父类、父接口)的功能,并可以增加它自己的新功能的能力。在Java中继承关系通过关键字extends明确标识,在设计时一般没有争议性。在UML类图设计中,继承用一条带空心三角箭头的实线表示,从子类指向父类,或者子接口指向父接口。

    2.实现关系

        实现指的是一个class类实现interface接口(可以是多个)的功能,实现是类与接口之间最常见的关系。在Java中此类关系通过关键字implements明确标识,在设计时一般没有争议性。在UML类图设计中,实现用一条带空心三角箭头的虚线表示,从类指向实现的接口。

    3.依赖关系

        简单的理解,依赖就是一个类A使用到了另一个类B,而这种使用关系是具有偶然性的、临时性的、非常弱的,但是类B的变化会影响到类A。比如某人要过河,需要借用一条船,此时人与船之间的关系就是依赖。表现在代码层面,为类B作为参数被类A在某个method方法中使用。在UML类图设计中,依赖关系用由类A指向类B的带箭头虚线表示。

     4.关联关系

         关联体现的是两个类之间语义级别的一种强依赖关系,比如我和我的朋友,这种关系比依赖更强、不存在依赖关系的偶然性、关系也不是临时性的,一般是长期性的,而且双方的关系一般是平等的。关联可以是单向、双向的。表现在代码层面,为被关联类B以类的属性形式出现在关联类A中,也可能是关联类A引用了一个类型为被关联类B的全局变量。在UML类图设计中,关联关系用由关联类A指向被关联类B的带箭头实线表示,在关联的两端可以标注关联双方的角色和多重性标记。

    5.聚合关系

       聚合是关联关系的一种特例,它体现的是整体与部分的关系,即has-a的关系。此时整体与部分之间是可分离的,它们可以具有各自的生命周期,部分可以属于多个整体对象,也可以为多个整体对象共享。比如计算机与CPU、公司与员工的关系等,比如一个航母编队包括海空母舰、驱护舰艇、舰载飞机及核动力攻击潜艇等。表现在代码层面,和关联关系是一致的,只能从语义级别来区分。在UML类图设计中,聚合关系以空心菱形加实线箭头表示。

    6.组合关系

        组合也是关联关系的一种特例,它体现的是一种contains-a的关系,这种关系比聚合更强,也称为强聚合。它同样体现整体与部分间的关系,但此时整体与部分是不可分的,整体的生命周期结束也就意味着部分的生命周期结束,比如人和人的大脑。表现在代码层面,和关联关系是一致的,只能从语义级别来区分。在UML类图设计中,组合关系以实心菱形加实线箭头表示。

    7.总结

       对于继承、实现这两种关系没多少疑问,它们体现的是一种类和类、或者类与接口间的纵向关系。其他的四种关系体现的是类和类、或者类与接口间的引用、横向关系,是比较难区分的,有很多事物间的关系要想准确定位是很难的。前面也提到,这四种关系都是语义级别的,所以从代码层面并不能完全区分各种关系,但总的来说,后几种关系所表现的强弱程度依次为:组合>聚合>关联>依赖。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值