三层Web应用程序项目的设计

50 阅读2分钟

在构建三层Web应用程序项目时,我们遇到了一个问题,那就是如何将业务逻辑与数据访问分离。我们有两个可行的方案,但需要在项目开始前做出决定。

huake_00063_.jpg 方案1:

将代码分为三层:

  • 第一层:Web界面
  • 第二层:信函处理
  • 第三层:ORM模型(sqlalchemy)

方案2:

将代码分为相同的三层,但在第二层只执行对用户集合的循环。生成HTML、发票和文章列表的方法都作为方法添加到ORM提供的第三层模型定义中。第二层执行循环,但实际功能封装在第三层的模型类中。

2、解决方案 经过讨论,我们认为这两种方案都可以,各有优缺点:

方案1的优点:

  • 完全将业务逻辑与数据库访问分离
  • 阻止导入ORM模型也导入我们可能不需要的大量方法/功能,还可以使模型类的代码更加紧凑
  • 在为测试模拟ORM模型时可能更容易使用

方案1的缺点:

  • 当需要在多个视图中使用业务逻辑时,可能会导致代码重复
  • 当需要测试业务逻辑时,可能会更难模拟

方案2的优点:

  • 似乎与Django在Python中处理事情的方式一致
  • 允许简单地访问方法:当存在模型实例时,可以立即调用它执行的任何函数
  • 可以传递实例,并拥有所有适当的方法

方案2的缺点:

  • 将所有业务逻辑都放在模型类中可能会导致代码难以维护
  • 在需要测试业务逻辑时,可能会更难模拟模型类

最终,我们选择方案1,因为我们认为它更能满足我们的要求。我们认为,将业务逻辑与数据访问分离可以使我们的代码更容易维护和测试。

代码示例:

# 第一层:Web界面
@app.route('/letters')
def letters():
    letters = Letter.query.all()
    return render_template('letters.html', letters=letters)

# 第二层:信函处理
class LetterService:
    def generate_html(self, letter):
        html = """
        <html>
        <body>
        <h1>Dear {letter.recipient_name},</h1>
        <p>Your order has been processed and is on its way to you.</p>
        <ul>
        {% for item in letter.items %}
        <li>{item.name} - {item.price}</li>
        {% endfor %}
        </ul>
        <p>Total: {letter.total_price}</p>
        </body>
        </html>
        """

        return html.format(letter=letter)

    def generate_invoice(self, letter):
        invoice = """
        Invoice No.: {letter.invoice_number}
        Date: {letter.date}
        Customer: {letter.recipient_name}
        Address: {letter.recipient_address}
        Items:
        {% for item in letter.items %}
        {item.name} - {item.price}
        {% endfor %}
        Total: {letter.total_price}
        """

        return invoice.format(letter=letter)

# 第三层:ORM模型
class Letter(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    recipient_name = db.Column(db.String(255))
    recipient_address = db.Column(db.String(255))
    invoice_number = db.Column(db.String(255))
    date = db.Column(db.Date)
    items = db.relationship('Item', backref='letter')
    total_price = db.Column(db.Float)

class Item(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(255))
    price = db.Column(db.Float)
    letter_id = db.Column(db.Integer, db.ForeignKey('letter.id'))