python 使用模板模式和工厂模式的混合设计开发各种邮件客户端发送邮件
1、使用模板模式和工厂模式的混合设计开发各种邮件客户端发送邮件。
2、模板模式的目的:能保证快速开发各种邮箱客户端,子类只需要重写模板类邮箱的抽象方法即可。之后再开发任何邮箱就只要加一个类,写3行代码就可以。
工厂模式的目的:能隐藏创建具体对象的细节,只需从工厂类的方法中就能得到各种邮箱客户端。例如被别的模块import时候,只需要import这个工厂类就可以了,不需要去import几十种具体的邮箱客户端。
# coding=utf8
"""
使用模板模式、工厂模式的混合设计,开发各种邮件客户端
"""
import sys reload(sys)
sys.setdefaultencoding('utf8') import re
import unittest
from abc import ABCMeta, abstractmethod
import smtplib
from email.mime.text import MIMEText class MailClient(object):
"""一个通用的邮件客户端,作为模板模式的模板类。
该类为抽象类,不可以进行实例化。
_set_smtp方法为抽象方法,子类必须重写这个方法.
"""
__metaclass__ = ABCMeta def __init__(self, msg_from, passwd):
"""
:param msg_from: 发件人邮箱地址
:param passwd: 发件人邮箱密码,qq邮箱使用授权码是16个字母,而不是自己的邮箱密码。
"""
self._mail_name = None
self._msg_from = msg_from
self._passwd = passwd
self._smtp = None
self._set_smtp()
self.__login() @abstractmethod
def _set_smtp(self):
pass def __login(self):
try:
self._smtp.login(self._msg_from, self._passwd)
except smtplib.SMTPAuthenticationError as e:
raise smtplib.SMTPAuthenticationError(535, '{}邮箱登录失败\n'.format(self._mail_name) + e.message) def send_mail(self, msg_to, subject, content):
"""
发送邮件
:param msg_to: 所有收件人的邮箱地址列表,类型为字符串列表,单个接收人也可以用字符串
:param subject :邮件主题
:param content:邮件内容
:return :邮件是否发送成功
:type msg_to:list
:type subject:str
:type content:str
"""
msg = MIMEText(content, _charset='utf8')
msg['Subject'] = subject
msg['From'] = self._msg_from
msg['To'] = msg_to
self._smtp.sendmail(self._msg_from, msg_to, msg.as_string())
print '邮件发送成功,发送的邮件主题是: {} 。请去邮箱检查邮件'.format(subject)
return True def __str__(self):
return '登录帐号为: {0} 的{1}邮箱客户端'.format(self._msg_from, self._mail_name) def quit(self):
try: # 如果没登陆成功就关闭连接,会出错,try一下
self._smtp.quit()
except:
pass def __del__(self):
self.quit() class QQMailClient(MailClient):
def _set_smtp(self):
self._mail_name = 'qq'
self._smtp = smtplib.SMTP_SSL("smtp.qq.com", 465) class Wangyi163MailClient(MailClient):
def _set_smtp(self):
self._mail_name = ''
self._smtp = smtplib.SMTP_SSL("smtp.163.com", 465) class MailNameException(Exception):
"""不支持的邮箱异常类"""
def __init__(self, msg_from):
err = '你设置的邮箱账号是 {} ,不支持此邮箱'.format(msg_from)
super(MailNameException, self).__init__(err) class MailClientFactory(object):
@staticmethod
def get_mail_client(msg_from, passwd):
"""
:param msg_from:发件人邮箱地址
:param passwd:邮箱密码
:return: 具体的邮箱对象
:type msg_from:str
:type passwd:str
:rtype :MailClient
"""
if re.match('[0-9a-zA-Z_]+@qq\.com', msg_from):
return QQMailClient(msg_from, passwd)
elif re.match('[0-9a-zA-Z_]+@163\.com', msg_from):
return Wangyi163MailClient(msg_from, passwd)
else:
raise MailNameException(msg_from) class MailTest(unittest.TestCase):
def test_163(self):
"""测试163邮箱发送两个邮件"""
wangyi163_mail_client = MailClientFactory.get_mail_client('m13148804506@163.com', '')
print wangyi163_mail_client
wangyi163_mail_client.send_mail('909686716@qq.com', '测试网易163邮箱发送主题1', '测试网易163邮箱发送内容1')
result = wangyi163_mail_client.send_mail('909686716@qq.com', '测试网易163邮箱发送主题2', '测试网易163邮箱发送内容2')
self.assertEqual(result, True, msg='163邮件发送失败') def test_qq(self):
"""测试两个qq号发送邮件"""
qq_123456_client = MailClientFactory.get_mail_client('123456@qq.com', 'ssoodruxniyfxxxx')
print qq_123456_client
qq_789000_client = MailClientFactory.get_mail_client('789000@qq.com', 'ssoodruxniyfxxxx')
print qq_789000_client
result = qq_123456_client.send_mail('m13148804506@163.com', '测试qq邮箱发送主题3', '测试qq邮箱发送内容3')
self.assertEqual(result, True, msg='qq邮件发送失败')
result = qq_789000_client.send_mail('m13148804506@163.com', '测试qq邮箱发送主题4', '测试qq邮箱发送内容4')
self.assertEqual(result, True, msg='qq邮件发送失败') def test_126(self):
"""测试一个不支持的邮箱"""
self.assertRaises(MailNameException, MailClientFactory.get_mail_client, 'm13148804506@126.com', '') if __name__ == "__main__":
unittest.main()
3、由此可见,在一个项目中设计模式不是固定的只能用一种,而是可以多种模式混合设计。
1、此项目也可以使用 策略模式来实现,策略类中设置邮箱服务器,Context类中登录和发送邮件,和此文比只有很小的区别。策略模式实现可以参考 http://www.cnblogs.com/ydf0509/p/8527515.html
2、由于这个邮箱项目比较简单,这也可以不使用设计模式,不需要增加多个类,只需要一个类就可以实现了。工厂模式的缺点是每次增加一个产品时,都需要增加一个具体类和对象实现工厂,使得系统中类的个数成倍增加,在一定程度上增加了系统的复杂度,同时也增加了系统具体类的依赖。过度设计这并不是什么好事。
3、也可以用面向过程来实现,缺点是在进行多实例操作时候,小红 小明 小黄登录qq邮箱,需要在类之外设置变量,如果类的属性非常多,比如20个,小红 、小黄 、小明需要在类外设置60个变量来保存这些属性,oop只要3个对象,每个对象有20个属性。oop在状态维护、保存、序列化反序列化上、被别的模块调用更简单、命名空间更清洁、继承这些方面有很大优势。
看到有的人是一个函数就实现发邮件,虽然简单,把设置服务、登录、发送邮件、关闭连接放一起了,那样做每发一个邮件都执行连接服务器进行登录发邮件关闭连接这个过程,有一些额外的开销。
python 使用模板模式和工厂模式的混合设计开发各种邮件客户端发送邮件的更多相关文章
- [python实现设计模式]-3.简单工厂模式-触宝开放平台
预备知识: 开放封闭原则(Open-Closed Principle OCP) Software entities(classes,modules,functions etc) should open ...
- javascript模式 (3)——工厂模式和装饰模式
上节我们讲解了单例模式,这节我们将继续讲解工厂模式和迭代器模式 工厂模式: 工厂模式的目的是为了方便的创建对象(可以在不知道构造的情况下),通过静态方法来实现,在java或c#等静态编译语言中需要通过 ...
- Java中的GOF23(23中设计模式)--------- 工厂模式(Factory)
Java中的GOF23(23中设计模式)--------- 工厂模式(Factory) 在给大家介绍工厂模式之前,我想和大家聊聊面向对象的那点事,在这里,引入三个概念. 开闭原则(Open Close ...
- Java设计模式之(工厂模式)--简单工厂模式--工厂方法模式--抽象工厂模式
工厂模式: 工厂模式可以分为三类: 1)简单工厂模式(Simple Factory) 2)工厂方法模式(Factory Method) 3)抽象工厂模式(Abstract Factory) 简单工厂模 ...
- Java中设计模式之工厂模式-4
一.工厂模式由来 1)还没有工厂时代:假如还没有工业革命,如果一个客户要一款宝马车,一般的做法是客户去创建一款宝马车,然后拿来用. 2)简单工厂模式:后来出现工业革命.用户不用去创建宝马车.因为客户有 ...
- JS 简单工厂模式,工厂模式(二)
一.什么是工厂模式: 工厂模式就是用来创建对象的一种最常用的设计模式,我们不暴露创建对象的具体逻辑,而是将逻辑封装到一个函数中,那么,这个函数 就可以被视为一个工厂.那么,在实际项目中,我们是不是可以 ...
- .Net简单工厂模式,工厂模式,抽象工厂模式实例
1.定义 简单工厂模式:是由一个工厂对象决定创建出哪一种产品类的实例.简单工厂模式是工厂模式家族中最简单实用的模式,可以理解为是不同工厂模式的一个特殊实现. 工厂模式:定义一个用于创建对象的接口, ...
- C#设计模式——简单工厂模式、工厂模式和抽象工厂模式
一:简单工厂模式 1:描述:简单工厂模式是由一个工厂对象根据接收到的消息决定要创建哪一个类的对象事例. 2:优点:工厂类中有相关逻辑判断,可以根据需要动态创建相关的对象事例,而客户端只需要告诉工厂类创 ...
- Java模式—简单工厂模式
简单工厂模式:是由一个工厂对象决定创建出哪一种产品类的实例,简单工厂模式是工厂模式家族中最简单实用的模式. 目的:为创建对象提供过渡接口,以便将创建对象的具体过程屏蔽隔离起来,达到提高灵活性的目的. ...
随机推荐
- Office2016无法显示最近使用的文档怎么办
来自:https://zhidao.baidu.com/question/1862342356245742187.html
- zookeeper快照清理
从3.4版本以后,在配置文件中有2个参数分别设置快照的清理.默认没有打开. autopurge.purgeInterval=1 这个参数指定了清理频率,单位是小时,需要填写一个1或更大的整数,默认是0 ...
- UMEditor(Ueditor mini)修改图片上传路径
UMEditor(Ueditor mini)修改图片上传路径 imageUp.ashx string pathbase = "/UpLoad/images/"; //保存文件夹在网 ...
- VS Code 如何直接在浏览器中预览页面
VS Code 预览html页面的时候,默认需要在资源管理器中显示,再在浏览器中预览.今天介绍一下如何直接预览html页面. 方法一:自己配置快捷键 1.ctrl + shift + p 或者 F1 ...
- js之队列01
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...
- [hadoop读书笔记]前言
hadoop2.0+主要变化: 全新的MapReduce 2,它建立在一个新的分布式资源管理系统之上,该系统称之为YARN. YARN:分布式资源管理系统
- JAVA中如何用接口实现多继承和多态 (非常好)
---------------------------------------------------------------多态1.JAVA里没有多继承,一个类之能有一个父类.而继承的表现就是多态. ...
- selenium(java)处理HTML5的视频播放
大多数浏览器使用控件(如 Flash) 来播放规频,但是,不同的浏览器需要使用不同的插件.HTML5 定义了一个新的元素<video>,,指定了一个标准的方式来嵌入电影片段.IE9+.Fi ...
- hash模块 hashlib不可逆加密 和 base64算法加密解密
hashlib模块 用于加密相关的操作,代替md5模块和sha模块,主要提供SHA1,SHA224,SSHA256,SHA384,SHA512,MD5算法 直接看代码案例: ---------md5- ...
- (笔记)Linux内核中内存相关的操作函数
linux内核中内存相关的操作函数 1.kmalloc()/kfree() static __always_inline void *kmalloc(size_t size, gfp_t flags) ...